【问题标题】:C# call generic interface method from non generic parent interface without dynamicC#从没有动态的非泛型父接口调用泛型接口方法
【发布时间】:2016-12-14 18:38:06
【问题描述】:

假设我们有一个非泛型基接口,带有一个泛型继承接口:

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

我需要创建一个返回 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
}

我能够让它工作的唯一方法是创建一个动态对象,而不是 IFoo,然后调用 Do() - 这在我的情况下确实有效,但我失去了一些我更喜欢的类型安全性保留。

我的问题是我是否可以重新设计它以便能够访问派生接口方法,同时仍然能够维护 IFoo 的列表(以及随后的工厂方法返回类型)????

【问题讨论】:

  • 要么将您的IFoo Get() 转换为BarImpl,要么过度考虑您的设计。除非你变得更具体,否则没什么可说的
  • 您的类型是IFoo;没有可以调用Do 的类型安全(这是IBar&lt;T, K&gt; 的一部分)。你认为这会如何工作?!
  • 使用 C# 6.0:(iFoo as IBar&lt;type1, type2&gt;).Do(typeof(type1));
  • 保持类型安全?我在此设计中看不到任何类型安全性。工厂返回IFoo,因此无法保证返回的类型实现IBar&lt;,&gt;,即使实现了,类型参数是什么。

标签: c# .net generics dynamic


【解决方案1】:

您期望或想要类型安全,但请这样想:

  • 为了能够调用DoGet 需要返回定义该方法的类型。 IFoo 没有,但 IBar&lt;T, K&gt; 有。 Get 但是返回一个 IFoo 对象,它不能保证是 IBar&lt;T, K&gt;
  • 即使 Get 的实现会确保只返回 IBar&lt;T, K&gt;,类型系统也无法在不实际返回该类型的情况下知道这一点
  • 假设您可以返回一个允许您调用Do 方法的类型,则该类型将不清楚:您需要将T 类型的对象传递给它。但是返回的IFooIBar&lt;T, K&gt; 不一定使用您想要传递给Do 的相同类型的T
  • 即使Get 的实现会提供这个(比如“给我一个接受T 类型的IBar&lt;T, K&gt;”)并且类型系统有办法反映这个,那么这仍然不会对K 说点什么。对于已知的T,它仍然可以是IBar&lt;T, int&gt;,或IBar&lt;T, string&gt;。如果没有具体的类型,实际上是无法知道这一点的。
  • 而且,假设这适用于类型系统:这实际上有什么用途?您可以使用正确的类型化参数调用泛型类型的方法:但返回值仍然没有具体类型。你不能对Do返回的类型说什么。

我的意思是,当您实际上有理由维护具体类型时,您只需要泛型类型。通常,如果您从另一个非泛型方法调用泛型方法或泛型类型的方法,那么您要么有一组离散的类型正在使用,要么您实际上不需要泛型类型信息。

所以也许你最好在这里引入一个非泛型 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);
    }
}

然后你可以让Get返回一个IBar,你就可以调用Do

顺便说一句。这种模式在 BCL 中非常常用,例如IEnumerable&lt;T&gt;IEnumerable

【讨论】:

  • 谢谢你,这看起来会奏效,非常感谢。
【解决方案2】:

您可以将object DoIt() 方法添加到IFoo,然后BarImpl 将实现它:

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

这里的问题是您需要将DoIt 的返回值转换为实际类型。但你不会先验地知道那是什么。

【讨论】:

  • 我相信 OP 代码中的 Type 类型只是一个示例,并不是字面意义上的 System.Type
猜你喜欢
  • 2012-03-01
  • 2017-11-13
  • 2011-03-14
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多