2014-04-30 21 views
6

Ho una classe con questo costruttore:Costruttore con parametro opzionale viola new() vincolo

public Currency(Guid? vcurrencyUI = null) 
    : base(vcurrencyUI) 
{ } 

e voglio usare questa classe con un vincolo new() ma ottengo questo errore:

'Currency' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method ...

Se ho diviso il tutto costruttore funziona bene:

public Currency(Guid? vcurrencyUI) 
    : base(vcurrencyUI) 
{ } 

public Currency() 
    : base() 
{ } 

perché ho bisogno di dividere il c onstructor?

risposta

15

Poiché un costruttore con un parametro predefinito non è un costruttore senza parametri.

I parametri predefiniti sono "compilati" dal compilatore in fase di compilazione. Quando si scrive:

var foo = new Currency(); 

il compilatore genera:

var foo = new Currency(null); 

Quando la classe è compilato, il compilatore crea un costruttore che prende quel parametro Guid?, e genera anche alcuni metadati che dice a tutti gli effetti "se il parametro non viene fornito in fase di compilazione, quindi fornire null. " Ma non viene generato alcun costruttore senza parametri per il tipo.

Il vincolo new() richiede la definizione di un costruttore senza parametri per il tipo e non accetta un costruttore con un singolo parametro predefinito. Molto probabilmente è perché il runtime, che finisce per dover chiamare il costruttore, non capisce il concetto di parametri di default.

+0

La risposta Jims è corretta. Per uno sguardo più approfondito a una domanda molto simile, vedere il mio articolo qui http://blog.coverity.com/2013/09/11/c-bug/ –

5

Anche se Jim already answered tua domanda, notare che un approccio più generale potrebbe essere quello di consentire il superamento di un delegato che istanziare la classe concreta, invece di costringere tutte le implementazioni di essere senza parametri.

I.e. invece di questo:

public class Something<T> where T : new() 
{ 
    public T CreateInstance() 
    { 
     return new T(); 
    } 
} 

è possibile passare un delegato esplicita che farà ogni logica esemplificazione personalizzato:

// note that the constraint is now removed 
public class Something<T> 
{ 
    private readonly Func<T> _ctor; 
    public Something(Func<T> ctor) 
    { 
     _ctor = ctor; 
    } 

    public T CreateInstance() 
    { 
     return _ctor(); 
    } 
} 

// and you can now pass arbitrary constructor logic as a delegate 
var x = new Something<Currency>(() => new Currency(null)); 

Questo permette anche di creare una classe di supporto ed avere entrambe le opzioni disponibili facilmente:

public class Something 
{ 
    // this allows you to use a parameterless ctor 
    public static Something<T> Create<T>() where T : new() 
    { 
     return new Something<T>(() => new T()); 
    } 

    // this allows you to specify a custom one 
    public static Something<T> Create<T>(Func<T> ctor) 
    { 
     return new Something<T>(ctor); 
    } 
} 
Problemi correlati