C#创建从base继承的Generic类的实例

时间:2016-05-28 08:58:04

标签: c# .net

我试图创建类Bar的实例,但我收到错误:

  

&#34;无法隐式转换类型ConsoleApplication1.Bar   ConsoleApplication1.BaseFoo<ConsoleApplication1.baseOutput, ConsoleApplication1.baseInput>&#34;

知道我错过了什么,或者我做错了什么?任何建议都会很好。

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

2 个答案:

答案 0 :(得分:3)

我将举例说明您为何无法这样做。

想象一下,你的课程写得像这样:

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

现在,你有这个方法:

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

所以,我们称之为:

var myBar = CreateInstance();

现在,mybar.Something的类型为 BaseOutput 。那很好,因为ExtendOutput : BaseOutput,对吗?不太好。

当我们这样做时会发生什么:

myBar.Something = new SomethingElse();

这是有效的,因为Something期望BaseOutput,而SomethingElseBaseOutput然而,该对象实际上是一个 Bar ,明确表示它应该是ExtendOutput

如果我们试图将其丢回,问题会更清楚:

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

这显然是错的。 您可以covariance使用此行为。

协方差使传递TOutput成为非法。那么,这一行

public TOutput Something { get; set; }

无效。我们只允许公开getter:

public TOutput Something { get; }

缓解了上述问题

答案 1 :(得分:1)

BarBaseFoo<ExtendOutput, ExtendInput>CreateInstance()要求BaseFoo<baseOutput, baseInput>返回,因此无法返回Bar BaseFoo<ExtendOutput, ExtendInput> }。

无论ExtendOutput是否继承baseOutput,当您继承泛型类时,继承为invariant

考虑使用带有inout通用修饰符的接口:

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();
    }
}