c# 转换泛型接口的非泛型实现

c# casting non generic implement of generic interface

我阅读了很多可能的答案,但没有找到适合我需要的答案!

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

这是我目前所拥有的:

接口

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# 打字变得不可能and/or 建议稍微复杂一些的模式来顺利完成

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

很明显,如果实际答案已经存在,很抱歉浪费时间

一如既往,没有上下文很难做到中肯,但我会尽力提供帮助。

错误 'Argument Type NonGenericImplementation1 is not assignable to IGenericInterface' 在我看来完全没问题,在 C# 中,集合的不同成员必须具有相同的类型。

但是你为什么声明:

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

而不是:

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

这样,您的所有示例代码仍然有效,并且两者 类 将实现相同的接口,因此您现在可以声明:

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

希望对您有所帮助。

IGenericInterface<WeirdType1> 不是 IGenericInterface<WeirdType>,即使 WeirdType1 实现了 WeirdType

问题是,如果你从 implementations 中取出一些东西,我们知道它的类型是 IGenericInterface<WeirdType>。这意味着我们应该能够调用 GiveT 并获得 WeirdTypeTakeItBack,同时将其传递给 WeirdType.

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

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

现在,如果 implNonGenericImplementation1 类型,则第二个无效,如果它是 NonGenericImplementation2 类型,则第一个无效。

这意味着我们不能声称 NonGenericImplementation1IGenericInterface<WeirdType> 类型并且 NonGenericImplementation2 也是如此。

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

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

这就是泛型的美妙之处。它们是强类型的,特别是当你处理泛型的泛型时,它变得更具挑战性。但是没有办法。

首先,Generic List 将不接受任何未实现 IGenericInterface 类型的对象。接下来,当您拥有那种 class 时,即使该类型是从 "WeirdType".[=12= 继承的,它也将不允许使用 "WeirdType" 以外的类型实例化的对象]

所以泛型中的继承在第一层有帮助,但除此之外就没有帮助了。

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

您需要创建子 class 如下。

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

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

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

这应该可以解决您的问题。

感谢大家的意见,我尽量不重复与 T 无关的代码,样板文件越少越好。

我采用的解决方案是添加抽象 class 实现额外的接口。

这并不令我满意,因为我相信您应该能够为泛型编写类型不可知的代码,因此无需修改实际的 classes 和接口 code/hierarchy 也不会滥用反射。

这可以通过扩展方法和 non-typed 泛型列表实现,后者在 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();
}