简体   繁体   English

C#强制转换通用接口的非通用实现

[英]c# casting non generic implement of generic interface

I read quite a lot of possible answers and didn't find any that could fit my needs ! 我读了很多可能的答案,但找不到适合我的需求!

I am trying to declare a generic interface, have different non-generic implementing classes and then use this classes in the same context. 我试图声明一个通用接口,具有不同的非通用实现类,然后在相同的上下文中使用此类。

This is what I have so far : 这是我到目前为止所拥有的:

Interfaces 介面

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


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

Implementations 实现

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

Usage 用法

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

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

This throws me 这把我扔了

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

and even if some black casting magic gets me through compilation it crashes at runtime for the same reason. 即使某些黑魔法使我通过编译,由于相同的原因它也会在运行时崩溃。

Help me understand what makes this impossible for C# typing and/or suggest slightly more complex patterns to get it done smoothly 帮助我了解是什么使C#键入无法实现和/或建议稍微复杂一些的模式以使其顺利完成

I can solve my actual problem a lot of different ways, so completely alternate solutions are not really what I am looking for 我可以用很多不同的方法解决实际问题,因此,完全替代的解决方案并不是我真正想要的

And obviously if the actual answer already exists sorry for the time wasting 而且很明显,如果实际答案已经存在,那很浪费时间

As always it's hard to be pertinent without context, still I'll do my best to help. 与往常一样,没有上下文很难做到恰当,我仍然会尽力提供帮助。

The error 'Argument Type NonGenericImplementation1 is not assignable to IGenericInterface' seems perfectly fine to me, in C# the different members of a collection must have the same type. 错误“参数类型NonGenericImplementation1无法分配给IGenericInterface”对我来说似乎很好,在C#中,集合的不同成员必须具有相同的类型。

But why do you declare : 但是为什么要声明:

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

Instead of: 代替:

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

In this way, all your example code will still work, and both classes will implement the same interface, so you can now declare: 这样,您的所有示例代码仍将起作用,并且两个类都将实现相同的接口,因此您现在可以声明:

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

Hope it helps. 希望能帮助到你。

即使WeirdType1实现WeirdTypeIGenericInterface<WeirdType1>也不是IGenericInterface<WeirdType>

The problem is that if you take something out of implementations we know it is of type IGenericInterface<WeirdType> . 问题是,如果您从implementations删除某些内容,我们知道它的类型为IGenericInterface<WeirdType> This means that we should be able to call GiveT and get a WeirdType and TakeItBack while passing it a WeirdType . 这意味着,我们应该能够调用GiveT并获得WeirdTypeTakeItBack同时传递一个WeirdType

In particular this means both of the following must work: 特别是,这意味着以下两项必须起作用:

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

Now if impl is of type NonGenericImplementation1 then the second is not valid and if it is of type NonGenericImplementation2 then the first is not valid. 现在,如果impl的类型为NonGenericImplementation1则第二个无效;如果impl的类型为NonGenericImplementation2则第一个无效。

This means that we are not allowed to claim that NonGenericImplementation1 is of type IGenericInterface<WeirdType> and the same for NonGenericImplementation2 . 这意味着我们不允许声称NonGenericImplementation1是类型的IGenericInterface<WeirdType>与同为NonGenericImplementation2

You do not have any non generic class which implements IGenericInterface . 您没有任何实现IGenericInterface的非通用类。

Your "implements" collection can only accept objects of type which implements above mentioned interface. 您的“实现”集合只能接受实现上述接口的类型的对象。

That's the beauty of Generics. 那就是泛型的美。 They are strongly typed and specially when you are dealing with Generics of Generics it becomes much more challenging. 它们是强类型的,特别是当您处理泛型的泛型时,它变得更具挑战性。 But there is not way out of it. 但是没有出路。

First of all Generic List will not accept any object of type which is not implementing IGenericInterface. 首先,通用列表将不接受任何未实现IGenericInterface的类型的对象。 Next when you have that kind of class it will also not allow the object which is instantiated with type other then "WeirdType" no matter even if the type is inherited from "WeirdType". 接下来,当您拥有此类时,即使该类型继承自“ WeirdType”,也不允许使用“ WeirdType”以外的其他类型实例化的对象。

So inheritance in Generics helps at the first level but not beyond that. 因此,泛型中的继承在第一层是有帮助的,但没有超出这一范围。

There is solution for your problem. 有解决您的问题的方法。 It's not a 100% valid solution, and many OOP Experts will not agree with this, but it has class structure you want and it works the way you want. 这不是一个100%有效的解决方案,许多OOP专家不会对此表示同意,但是它具有所需的类结构,并且可以按所需的方式工作。

You need to create sub classes as following. 您需要如下创建子类。

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

Now you can initialize the collection of Generic interface and add objects of sub classes into it. 现在,您可以初始化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);
        }

This should resolve your issue. 这样可以解决您的问题。

Thanks everyone for your input, I was tryng not to repeat code that was T agnostic, with as less boilerplate as possible. 感谢大家的投入,我尽量不重复与T无关的代码,并尽可能减少样板。

The solution I went with was adding an abstract class implementing an extra interface. 我所采用的解决方案是添加一个实现额外接口的抽象类。

This does not satisfy me as I believe you should be able to write type agnostic code for generics, and thus without modifying the actual classes and interfaces code/hierarchy nor abusing reflexion. 这让我不满意,因为我相信您应该能够为泛型编写类型不可知的代码,从而无需修改实际的类和接口代码/层次结构或滥用反射。

That would be possible with extension methods and non-typed list of generics, the later not being supported in C#. 扩展方法和泛型的非类型化列表将是可能的,C#不支持后者。

Heres the extra code : 这是额外的代码:

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

Classes declaration : 类声明:

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

Usage : 用法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM