c#cast非泛型通用接口的实现

时间:2017-01-25 15:37:23

标签: c# generics theory typing

我读了很多可能的答案,并没有找到任何符合我需要的答案!

我试图声明一个通用接口,有不同的非通用实现类,然后在同一个上下文中使用这个类。

这是我到目前为止所做的:

接口

public interface WeirdType { }
public class WeirdType1 : WeirdType { }
public class WeirdType2 : WeirdType { }


public interface IGenericInterface<T>
{
  T GiveT();
  void TakeItBack(T data);
}

实施

public class NonGenericImplementation1 : IGenericInterface<WeirdType1>
{
  public WeirdType1 GiveT() { return new WeirdType1(); }
  public void TakeItBack(WeirdType1 data) { Console.WriteLine("Got it back 1"); }
}

public class NonGenericImplementation2 : IGenericInterface<WeirdType2>
{
  public WeirdType2 GiveT() { return new WeirdType2(); }
  public void TakeItBack(WeirdType2 data) { Console.WriteLine("Got it back 2"); }
}

用法

List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>>
{
  new NonGenericImplementation1(),
  new NonGenericImplementation2()
};

foreach (var impl in implementations)
{
  WeirdType x = impl.GiveT();
  impl.TakeItBack(x);
}

这让我失望

'Argument Type NonGenericImplementation1 is not assignable to IGenericInterface<WeirdType>' 

即使一些黑色魔法让我通过编译,它也会在运行时因同样的原因而崩溃。

帮助我理解是什么让C#打字变得不可能和/或建议稍微复杂的模式来顺利完成

我可以用很多不同的方式解决我的实际问题,所以完全替代的解决方案并不是我真正想要的

显然,如果实际答案已经存在,那就是浪费时间

5 个答案:

答案 0 :(得分:0)

一如既往,如果没有背景,很难相关,我仍然会尽力帮助。

错误&#39;参数类型NonGenericImplementation1不能分配给IGenericInterface&#39;对我来说似乎完全没问题,在C#中,集合的不同成员必须具有相同的类型。

但你为什么宣布:

<div id="1">test</div>
<div id="2">test</div>
<div id="3">test</div>
<div id="4">test</div>

而不是:

public class NonGenericImplementation1 : IGenericInterface<WeirdType1>
public class NonGenericImplementation2 : IGenericInterface<WeirdType2>

通过这种方式,所有示例代码仍然可以工作,并且两个类都将实现相同的接口,因此您现在可以声明:

public class NonGenericImplementation1 : IGenericInterface<WeirdType>
public class NonGenericImplementation2 : IGenericInterface<WeirdType>

希望它有所帮助。

答案 1 :(得分:0)

即使IGenericInterface<WeirdType1>实施IGenericInterface<WeirdType>WeirdType1也不是WeirdType

答案 2 :(得分:0)

问题在于,如果您从implementations中取出某些内容,我们就知道它属于IGenericInterface<WeirdType>类型。这意味着我们应该能够调用GiveT并获得WeirdTypeTakeItBack,同时向其传递WeirdType

特别是这意味着以下两项都必须有效:

impl.TakeItBack(new WeirdType1());
impl.TakeItBack(new WeirdType2());

现在,如果impl的类型为NonGenericImplementation1,则第二个无效,如果类型为NonGenericImplementation2,则第一个无效。

这意味着我们不得声称NonGenericImplementation1属于IGenericInterface<WeirdType>类型且NonGenericImplementation2属性相同。

答案 3 :(得分:0)

您没有任何实现IGenericInterface的非泛型类。

您的“implements”集合只能接受实现上述接口的类型的对象。

这就是泛型的美丽。它们是强类型的,特别是在处理泛型泛型时,它变得更具挑战性。但是没有办法摆脱它。

首先,Generic List不接受任何未实现IGenericInterface的类型的对象。接下来,当你拥有那种类时,它也不允许使用“WeirdType”类型实例化的对象,即使该类型是从“WeirdType”继承的。

因此,泛型中的继承有助于第一级但不能超越它。

您的问题有解决方案。它不是100%有效的解决方案,许多OOP专家都不会同意这一点,但它有你想要的类结构,它可以按照你想要的方式工作。

您需要创建以下子类。

public class GenericClass<T> : IGenericInterface<T> where T : WeirdType
{
    public virtual T GiveT()
    {
        return default(T);
    }

    public virtual void TakeItBack(T data)
    {

    }
}

public class NonGenericClass1 : GenericClass<WeirdType1>, IGenericInterface<WeirdType>
{
    public override WeirdType1 GiveT()
    {
        return new WeirdType1();
    }

    public void TakeItBack(WeirdType data)
    {
        Console.WriteLine("Got it back 1");
    }

    public override void TakeItBack(WeirdType1 data)
    {
        this.TakeItBack(data);
    }

    WeirdType IGenericInterface<WeirdType>.GiveT()
    {
        return GiveT();
    }
}

public class NonGenericClass2 : GenericClass<WeirdType2>, IGenericInterface<WeirdType>
{
    public WeirdType2 GiveT()
    {
        return new WeirdType2();
    }

    public void TakeItBack(WeirdType data)
    {
        Console.WriteLine("Got it back 2");

    }

    public override void TakeItBack(WeirdType2 data)
    {
        this.TakeItBack(data);
    }

    WeirdType IGenericInterface<WeirdType>.GiveT()
    {
        return this.GiveT();
    }
}

现在您可以初始化Generic接口的集合并将子类的对象添加到其中。

var obj1 = new NonGenericClass1();
        var obj2 = new NonGenericClass2();
        List<IGenericInterface<WeirdType>> implementations = new List<IGenericInterface<WeirdType>>
        {
           obj1, obj2
        };

        foreach (var impl in implementations)
        {
            WeirdType x = impl.GiveT();
            impl.TakeItBack(x);
        }

这可以解决您的问题。

答案 4 :(得分:0)

感谢大家的意见,我试着不要重复与T不可知的代码,尽可能减少样板。

我使用的解决方案是添加一个实现额外接口的抽象类。

这不满足我,因为我相信你应该能够为泛型编写类型不可知的代码,因此不需要修改实际的类和接口代码/层次结构,也不会滥用反射。

对于扩展方法和非类型的泛型列表,这是可能的,后者在C#中不受支持。

下面是额外的代码:

public interface IComplexable { void DoComplexStuff(); }

public abstract class GenericImplementation<T> : IGenericInterface<T>, IComplexable
{
    public abstract T GiveT();
    public abstract void TakeItBack(T data);

    public void DoComplexStuff()
    {
        T x = GiveT();
        TakeItBack(x);
    }
}

课程声明:

public class NonGenericImplementation1 : GenericImplementation<WeirdType1>
public class NonGenericImplementation2 : GenericImplementation<WeirdType2>

用法:

var impl = new IComplexable[] { new NonGenericImplementation1(),new NonGenericImplementation2() };
foreach (var complexable in impl)
{
  complexable.DoComplexStuff();
}