2016-05-28 15 views
5

Próbuję utworzyć instancję klasy bar, ale ja dostaję błąd:C# Tworzenie instancji klasy rodzajowy które dziedziczenie z bazy

"Cannot implicitly convert type ConsoleApplication1.Bar to ConsoleApplication1.BaseFoo<ConsoleApplication1.baseOutput, ConsoleApplication1.baseInput> "

Każdy pomysł co mi brakuje lub co mam robić źle? Każda rada będzie miła.

public class baseOutput 
{ 
    public string output; 
} 

public class baseInput 
{ 
    public string input; 
} 

public class ExtendOutput : baseOutput 
{ 
    public long id; 
} 

public class ExtendInput : baseInput 
{ 
    public long id; 
} 

public class BaseFoo<baseOutput, baseInput> 
{ 
    protected virtual void DoSmth() 
    { 

    } 
} 

public class Bar : BaseFoo<ExtendOutput, ExtendInput> 
{ 
    protected override void DoSmth() 
    { 
     base.DoSmth(); 
    } 
} 

public class Test 
{ 
    public void Show() 
    { 

    } 

    private BaseFoo<baseOutput, baseInput> CreateInstance() 
    { 
     return new Bar(); // Error right here 
    } 
} 
+5

Tylko dlatego 'A: B' i' C: d', nie oznacza, że ​​'a : B '. Wyszukaj kowariancję w języku C# - pozwoli ci to zrobić, co chcesz, z kilkoma ograniczeniami. – Rob

+0

Należy trzymać się konwencji kodowania C#; "public class BaseFoo " wprowadza w błąd, ponieważ masz klasy o tych samych nazwach (baseOutput i baseInput). – enkryptor

Odpowiedz

3

Dam ci przykład, dlaczego nie możesz tego zrobić.

Wyobraź zamiast Twoje zajęcia zostały napisane tak:

public class BaseFoo<TOutput, TInput> 
    where TOutput : BaseOutput 
{ 
    public TOutput Something { get; set; } 
} 

public class Bar : BaseFoo<ExtendOutput, ExtendInput> 
{ 

} 

public class BaseInput { } 
public class BaseOutput { } 
public class ExtendOutput : BaseOutput { } 
public class SomethingElse : BaseOutput { } 

Teraz masz tą metodą:

private BaseFoo<BaseOutput, BaseInput> CreateInstance() 
{ 
    //At this point, Something will be of type ExtendOutput. 
    return new Bar(); 
} 

Tak, nazywamy to tak:

var myBar = CreateInstance(); 

Teraz mybar.Something jest typu BaseOutput. W porządku, bo ExtendOutput : BaseOutput, prawda? Nie do końca.

Co się dzieje, kiedy to zrobić:

myBar.Something = new SomethingElse(); 

To ważne, ponieważ Something oczekuje BaseOutput i SomethingElse jest BaseOutput. Jednak w przypadku obiektu obiekt jest w rzeczywistości taktyką, która wyraźnie mówi, że powinna to być ExtendOutput.

Problemem jest wyraźniejszy, jeśli spróbujemy oddać go z powrotem:

var myBaseFoo = CreateInstance(); 
myBaseFoo.Something = new SomethingElse(); 
Bar myBar = (Bar)myBaseFoo; 
myBar.Something; // Here, we're told it's going to be an `ExtendOutput`, 
       // but we get a `SomethingElse`? 

to wyraźnie źle. I czyli, dlaczego nie możesz robić tego, co próbujesz zrobić. Możesz mieć to zachowanie z covariance.

Kowariancja powoduje, że nielegalne jest przekazywanie w postaci TOutput. Tak więc ta linia będzie niepoprawna. Chcemy być dozwolone jedynie w celu odsłonięcia getter:

public TOutput Something { get; } 

Która łagodzi powyższy problem

1

Bar jest BaseFoo<ExtendOutput, ExtendInput> i CreateInstance() wymaga BaseFoo<baseOutput, baseInput> zostać zwrócone, więc nie mogą wrócić Bar który BaseFoo<ExtendOutput, ExtendInput>.

Bez względu na to, czy ExtendOutput dziedziczy baseOutput, po odziedziczeniu klasy ogólnej dziedziczenie to invariant.

Zastanów się nad wykorzystaniem interfejsów z in i out generycznych modyfikatorów:

public class baseOutput 
{ 
    public string output; 
} 

public class baseInput 
{ 
    public string input; 
} 

public class ExtendOutput : baseOutput 
{ 
    public long id; 
} 

public class ExtendInput : baseInput 
{ 
    public long id; 
} 

public interface IBaseFoo<out T1, out T2> 
{ 
    public void DoSmth(); 
} 

public class Bar : IBaseFoo<ExtendOutput, ExtendInput> 
{ 
    public void DoSmth() 
    { 

    } 
} 

public class Test 
{ 
    public void Show() 
    { 

    } 

    private IBaseFoo<baseOutput, baseInput> CreateInstance() 
    { 
     return new Bar(); 
    } 
} 
Powiązane problemy