2016-05-28 12 views
5

Tôi đang cố gắng để tạo ra thể hiện của lớp Bar nhưng tôi nhận được một lỗi:C# Tạo Instance của lớp Generic mà thừa kế từ cơ sở

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

Bất kỳ ý tưởng những gì tôi đang thiếu hoặc những gì tôi làm sai? Mọi lời khuyên sẽ tốt đẹp.

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

Chỉ vì 'A: b' và 'C: D', không có nghĩa là' Một : B '. Tra cứu hiệp phương sai trong C# - nó sẽ cho phép bạn làm những gì bạn đang cố gắng, với một vài hạn chế. – Rob

+0

Hãy gắn bó với quy ước mã hóa C#; "public class BaseFoo " là gây hiểu nhầm vì bạn có các lớp có cùng tên (baseOutput và baseInput). – enkryptor

Trả lời

3

Tôi sẽ cung cấp cho bạn ví dụ về lý do tại sao bạn không được làm điều đó.

Hãy tưởng tượng thay vào đó, lớp học của bạn được viết như thế này:

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 { } 

Bây giờ, bạn có phương pháp này:

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

Vì vậy, chúng tôi gọi nó là như thế này:

var myBar = CreateInstance(); 

Hiện tại, mybar.Something thuộc loại BaseOutput. Đó là tốt, tuy nhiên, bởi vì ExtendOutput : BaseOutput, phải không? Không hẳn.

gì xảy ra khi chúng ta làm điều này:

myBar.Something = new SomethingElse(); 

Đó là hợp lệ, vì Something hy vọng một BaseOutput, và SomethingElse là một BaseOutput. Tuy nhiên, đối tượng thực sự là một thanh , rõ ràng là nó phải là ExtendOutput.

Vấn đề là rõ ràng hơn nếu chúng ta cố gắng để cast nó trở lại:

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`? 

Đó là rõ ràng là sai. Và đó là lý do bạn bị ngăn không làm những gì bạn đang cố gắng làm. Bạn có thể có hành vi này với covariance.

Hiệp phương sai làm cho nó bất hợp pháp để vượt qua trong một TOutput. Vì vậy, dòng này

public TOutput Something { get; set; } 

Sẽ không hợp lệ. Chúng tôi sẽ chỉ được phép tiếp xúc với các getter:

public TOutput Something { get; } 

nào làm giảm bớt các vấn đề trên

1

BarBaseFoo<ExtendOutput, ExtendInput>, và CreateInstance() đòi hỏi BaseFoo<baseOutput, baseInput> để được trả lại, vì vậy nó không thể trở về Bar đó là BaseFoo<ExtendOutput, ExtendInput>.

Bất kể ExtendOutput được thừa hưởng baseOutput, khi bạn kế thừa một lớp chung kế thừa là invariant.

Xem xét sử dụng giao diện với inout bổ chung:

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(); 
    } 
} 
Các vấn đề liên quan