简体   繁体   English

C#从非通用父接口调用通用接口方法而无需动态

[英]C# call generic interface method from non generic parent interface without dynamic

Say we have a non generic base interface, with a generic inheriting interface: 假设我们有一个非通用的基本接口,带有一个通用的继承接口:

public interface IFoo { }
public interface IBar<T, K> : IFoo { 
    K Do(T t);
}

public class BarImpl : IBar<Type, AnotherType> {
    public AnotherType Do(Type type) {
        return new AnotherType(type);
    }
}

I need to create a factory which returns an IFoo instance, but using the returned instance I need to be able to call the derived types Do(T), which isn't available. 我需要创建一个返回IFoo实例的工厂,但是使用返回的实例,我需要能够调用派生类型Do(T),该类型不可用。

public class FooFactory() {
    IFoo Get() {
           // simplified, in reality i am returning the correct
           // type by checking the generic interface
           // types to get an object from a stored list 
           // of implementations
           return BarImpl();
    }
}

// Now in another class
public void DoFoo() {
    IFoo iFoo = new FooFactory().Get();
    // Need to be able to call iFoo.Do(Type) but cannot
}

The only way I have been able to get this to work is to create a dynamic object, instead of IFoo, and then call Do() - which does work in my case but I lose some type safety which i'd prefer to keep. 我能够使它起作用的唯一方法是创建一个动态对象而不是IFoo,然后调用Do()-在我的情况下确实有效,但是我失去了一些我希望保留的类型安全性。

My question is can I re-engineer this to be able to get access to the derived interfaces method, whilst still being able to maintain a list (and subsequently factory method return type) of IFoo???? 我的问题是我可以对此进行重新设计,以便能够访问派生的接口方法,同时仍然能够维护IFoo的列表(以及随后的工厂方法返回类型)吗?

You expect or want type safety, but think about it this way: 您期望或想要类型安全性,但是可以这样考虑:

  • In order to be able to call Do , Get needs to return a type which defines that method. 为了能够调用DoGet需要返回定义该方法的类型。 IFoo does not have it, but IBar<T, K> does. IFoo没有它,但是IBar<T, K>有。 Get however returns an IFoo object which is not guaranteed to be a IBar<T, K> . 但是, Get返回一个IFoo对象,该对象不能保证是IBar<T, K>
  • Even if the implementation of Get would make sure that only a IBar<T, K> is returned, there is no way the type system would know this without actually returning that type . 即使Get的实现可以确保仅返回IBar<T, K> ,类型系统也不会在不实际返回该类型的情况下知道这一点
  • Assuming you could return a type that allowed you to call the Do method, the type would be unclear: You need to pass it an object of type T . 假设您可以返回允许您调用Do方法的类型,则该类型尚不清楚:您需要向其传递类型为T的对象。 But the returned IFoo or IBar<T, K> does not necessarily use the same type T that you wanted to pass to Do . 但是返回的IFooIBar<T, K>不一定使用您想要传递给Do的相同类型T
  • Even if the implementation of Get would provide this (like “Get me an IBar<T, K> that accepts the type T ”) and the type system would have a way to reflect this, then this still wouldn't say anything about K . 即使Get的实现可以提供此信息(例如“给我一个接受类型TIBar<T, K> ”),并且类型系统也有办法反映这一点,那么对于K来说,它什么也没说。 For a known T , it could still be an IBar<T, int> , or an IBar<T, string> . 对于已知的T ,它仍然可以是IBar<T, int>IBar<T, string> And there is actually no way to know that without actually having the concrete type. 如果没有实际的类型,实际上是没有办法知道的。
  • And still, assuming that this would work with the type system: What purpose would this actually serve? 而且,仍然假定这适用于类型系统:这实际上有什么作用? You could call the method of your generic type with your correct typed argument: But the return value still has no concrete type. 您可以使用正确的类型化参数调用通用类型的方法:但是返回值仍然没有具体类型。 You couldn't say anything about the returned type from Do . 您无法说出Do返回的类型。

My point is that you only need generic types, when you actually have a reason to maintain a concrete type. 我的观点是,当您实际上有理由维护具体类型时,只需要通用类型。 Usually if you call a generic method or a method of a generic type from another non-generic method, then you either have a discrete set of types you're working with, or you don't actually need the generic type information. 通常,如果您从另一个非泛型方法中调用一个泛型方法或一个泛型类型的方法,那么您要么拥有一组正在使用的离散类型,要么实际上不需要泛型类型信息。

So maybe you're better off introducing a non-generic IBar type here: 因此,也许最好在这里引入非通用的IBar类型:

interface IBar
{
    object Do(object t);
}
interface IBar<T, K> : IBar
{
    K Do(T t);
}

public class BarImpl : IBar<Type, AnotherType>
{
    public AnotherType Do(Type type)
    {
        return new AnotherType(type);
    }

    public object Do(object t)
    {
        return Do((Type) t);
    }
}

Then you could make Get return an IBar instead, and you have a way to call Do . 然后,你可以把Get返回的IBar ,而是和你有一个方法来调用Do

Btw. 顺便说一句。 this pattern is used pretty commonly in the BCL, eg IEnumerable<T> and IEnumerable . 此模式在BCL中非常常用,例如IEnumerable<T>IEnumerable

You could add a object DoIt() method to IFoo , then BarImpl would implement it: 您可以在IFoo添加一个object DoIt()方法,然后BarImpl将其实现:

public object DoIt()
{
    return Do(typeof(T));
}

The problem here is that you would then need to cast the return of DoIt to the actual type. 这里的问题是您然后需要将DoIt的返回值DoIt转换为实际类型。 But you won't know apriori what that is. 但是您不会知道apriori是什么。

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

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