2014-04-30 6 views
6

Mam klasy z tego konstruktora:Konstruktor z opcjonalnym parametrem jest niezgodny new() ograniczenie

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

i chcę skorzystać z tej klasy z new() przymusu, ale pojawia się ten błąd:

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

Gdybym podzielić konstruktor wszystko działa poprawnie:

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

public Currency() 
    : base() 
{ } 

dlaczego muszę podzielić c onstructor?

Odpowiedz

15

Ponieważ konstruktor z parametrem domyślnym nie jest konstruktem bez parametrów.

Parametry domyślne są "wypełniane" przez kompilator podczas kompilacji. Kiedy piszesz:

var foo = new Currency(); 

Kompilator generuje:

var foo = new Currency(null); 

gdy klasa jest kompilowany, kompilator tworzy konstruktor, który zatrzymuje Guid? parametr, a także generuje pewne metadane, które mówi w efekcie „if parametr nie jest dostarczany w czasie kompilacji, a następnie podaj null. " Ale dla tego typu nie jest generowany konstruktor bez parametrów.

Ograniczenie new() wymaga zdefiniowania konstruktora bez parametrów dla danego typu i nie zaakceptuje konstruktora z pojedynczym domyślnym parametrem. Najprawdopodobniej dzieje się tak dlatego, że środowisko wykonawcze, które kończy się wywoływaniem konstruktora, nie rozumie pojęcia parametrów domyślnych.

+0

Odpowiedź Jims jest poprawna. Aby uzyskać bardziej szczegółowe spojrzenie na bardzo podobne pytanie, zobacz mój artykuł tutaj http://blog.coverity.com/2013/09/11/c-bug/ –

5

Choć Jim already answered swoje pytanie, trzeba pamiętać, że bardziej ogólne podejście może być, aby umożliwić przepuszczanie delegata które swoją konkretną instancję klasy, zamiast zmuszać wszystkie implementacje być bez parametrów.

tj. Zamiast tego:

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

można przekazać wyraźny delegata, który zrobi żadnej logiki zwyczaj instancji:

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

ta pozwala również utworzyć klasy pomocnika i mieć obie opcje łatwo dostępny:

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); 
    } 
} 
Powiązane problemy