2014-04-30 23 views
6

ich eine Klasse mit diesem Konstruktor:Constructor mit optionalen Parametern verletzt new() Einschränkung

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

und ich mag mit einem new() Zwang diese Klasse verwenden, aber ich bekomme diese Fehlermeldung:

'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 ...

Wenn ich teilten der Konstruktor funktioniert alles einwandfrei:

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

public Currency() 
    : base() 
{ } 

warum brauche ich die c aufzuspalten Konstrukteur?

Antwort

15

Da ein Konstruktor mit einem Standardparameter kein parameterloser Konstruktor ist.

Default-Parameter werden vom Compiler zur Kompilierzeit "ausgefüllt". Wenn Sie schreiben:

var foo = new Currency(); 

Der Compiler generiert:

var foo = new Currency(null); 

Wenn die Klasse kompiliert wird, der Compiler einen Konstruktor erstellt, dass Guid? Parameter annimmt und erzeugt auch einige Metadaten, die in der Tat sagt „, wenn der Parameter wird nicht zur Kompilierzeit geliefert, dann liefern Sie null. " Für den Typ wird jedoch kein parameterloser Konstruktor generiert.

Die Einschränkung new() erfordert, dass ein parameterloser Konstruktor für den Typ definiert wird und kein Konstruktor mit einem einzelnen Standardparameter akzeptiert wird. Wahrscheinlich liegt das daran, dass die Laufzeitumgebung, die letztendlich den Konstruktor aufrufen muss, das Konzept der Standardparameter nicht versteht.

+0

Jims Antwort ist korrekt. Für einen eingehenderen Blick auf eine sehr ähnliche Frage siehe meinen Artikel hier http://blog.coverity.com/2013/09/11/c-bug/ –

5

Obwohl Jim already answered Ihre Frage, beachten Sie, dass ein allgemeiner Ansatz könnte Gabe eines Delegierten zu ermöglichen sein, die Ihre konkreten Klasse instanziiert würde, anstatt alle Ihre Implementierungen zwingen parameterlos zu sein.

I.e. statt dessen:

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

Sie können einen expliziten Delegaten übergeben, die alle benutzerdefinierten Instanziierung Logik tun:

// 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)); 

Dies auch Sie eine Hilfsklasse erstellen können und haben beide Optionen leicht verfügbar:

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); 
    } 
} 
Verwandte Themen