了解使用泛型参数作为基接口返回Derived类

时间:2017-08-25 13:38:21

标签: c# generics

我有一种情况,我想创建一个类的实例,具体取决于作为参数传入的接口的实现。

public interface IFooParameters
{
    int Id { get; }
}

public interface IFooParametersAdditional
{
    int AnotherProperty { get; }
}

public class FooBarParameters : IFooParameters
{
    public int Id { get; set; } = 1;
    public int Bar { get; set; } = 42;
}

public class FooBazParameters : FooBarParameters, IFooParametersAdditional
{
    public int Baz { get; set; } = 55;
    public int AnotherProperty { get; set; } = 99;
}

public interface IFoo<in TFooParameters>
    where TFooParameters : IFooParameters
{
    void DoStuff(TFooParameters parameters);
}

public class Bar : IFoo<FooBarParameters>
{
    public void DoStuff(FooBarParameters parameters)
    {
        throw new System.NotImplementedException();
    }
}

public class Baz : IFoo<FooBazParameters>
{
    public void DoStuff(FooBazParameters parameters)
    {
        throw new System.NotImplementedException();
    }
}

public class Another : IFoo<FooBazParameters>
{
    public void DoStuff(FooBazParameters parameters)
    {
        throw new System.NotImplementedException();
    }
}

public interface IFooFactory
{
    IFoo<IFooParameters> GetInstance(IFooParameters parameters);
}

public class FooFactory : IFooFactory
{
    public IFoo<IFooParameters> GetInstance(IFooParameters parameters)
    {
        if (parameters.Id == 1)
            return new Bar(); // *** compiler error

        if (parameters.Id == 2)
            return new Baz(); // *** compiler error

        return new Another(); // *** compiler error
    }
}

// *** compiler error是:

  

错误CS0266无法将类型'Bar'隐式转换为'IFoo<IFooParameters>'。存在显式转换(您是否错过了演员?)

我不知道为什么我会这样做,因为我认为派生的实现应该(我会想到)隐式转换为Bar : IFoo<FooBarParameters>FooBarParameters : IFooParameters的基础这是有效的(不引入泛型):

public interface IBar { }
public class BarBar : IBar { }

public class Test
{
    public IBar Thing()
    {
        return new BarBar();
    }
}

我希望实现的基本思想是,IFooParameters有两种可能的实现传递到FooFactory,具体取决于类型和一些验证,返回{的实例{1}} - 我只关心返回接口,因为IFoo<IFooParameter>的所有实现之间的底层API是相同的,尽管一个实现需要通过IFoo<IFooParameters添加一个属性。

我对仿制药很陌生,所以我不确定我尝试做的事情是完全错误的,还是我在实现中遗漏了一些东西。但是对于正在发生的事情的任何帮助和/或解释都表示赞赏。

小提琴: https://dotnetfiddle.net/wjyLS7

使用演员略有变化: https://dotnetfiddle.net/ZFQjCn

1 个答案:

答案 0 :(得分:3)

如果编译器允许您将std::map实例转换为Bar,那么您将能够在IFoo<IFooParameters>实例中传递的返回值上调用DoStuff作为参数,但FooBazParameters实例仅允许接收Bar个实例。阻止您以无效方式使用FooBarParameters实例的唯一方法是阻止转换生效。