简体   繁体   English

我如何获得通用接口的接口实现

[英]how can i get the interface implementation of a generic interface

I have a class with the following class/interface structures:我有一个具有以下类/接口结构的类:

public class Foo : IBar<FooBar>, INonGenericBar
{
    // class implementation
     public override IsGeneric => return true;
     public override IsNonGeneric => return true;
}

public IBar<T>
{
    bool isGeneric {get;}
}

public INonGenericBar
{
    bool IsNonGeneric {get;}
}

I know can get the implementation of INonGenericBar with the is and as keywords;我知道可以使用isas关键字获得 INonGenericBar 的实现;

var myFoo = new Foo();
var barIsNonGeneric = myFoo is INonGenericBar;
Assert.IsTrue(barIsNonGeneric);
var nonGenericBar = myFoo as INonGeneric;
Assert.IsTrue(nonGenericBar.IsNonGeneric);

but since IBar is a generic interface, it seems I need to know the exact generic implemenatation但由于 IBar 是一个通用接口,看来我需要知道确切的通用实现

var myFoo = new Foo();
var isGenericBar = myFoo is IBar<FooBar>
var isParentGenericBar = myFoo is IBar<object>

Assert.IsTrue(isGenericBar);
Assert.IsFalse(isParentGenericBar);

var GenericBar = myFoo as IBar<FooBar>;
var GenericParentBar = myFoo as IBar<object>;

Assert.IsNotNull(GenericBar);
Assert.IsNotNull(GenericParentBar); // fails

I am however only intrested in the IBar<> interface itself, not the generic type it uses.然而,我只对 IBar<> 接口本身感兴趣,而不是它使用的通用类型。 Is there a way for me I can cast it to IBar<>?有没有办法让我可以将它投射到 IBar<>?

C# does not support the concept of "generic types, but I don't care about the type parameters" - this is why many libraries with generic classes put all of their non-generic members in a non-generic superclass (or generic interfaces putting their non-generic members in a non-generic parent interface). C# 不支持“泛型类型,但我不关心类型参数”的概念 - 这就是为什么许多具有泛型类的库将其所有非泛型成员放在非泛型超类中(或泛型接口放入它们在非通用父接口中的非通用成员)。 1 1

(Oddly enough, Java does support this scenario , but (ironically) this is only because Java's generics are implemented using type-erasure instead of .NET's reified-generics 1 ) (奇怪的是, Java确实支持这种情况,但(具有讽刺意味的是)这只是因为 Java 的泛型是使用类型擦除而不是 .NET 的具体泛型1 实现的

That said, C# does let you get the "open type" of a generic type with typeof operator - but only in the context of runtime reflection - so you cannot use it in normal program code.也就是说,C#确实允许您使用typeof运算符获得泛型类型的“开放类型” - 但仅限于运行时反射的上下文 - 因此您不能在正常程序代码中使用它。

So this is okay:所以这没问题:

Type openType = typeof(IBar<>);

But this is not:但这不是:

IBar<> anyIBar = ...

The only solution in C# is to refactor-move all of the members of IBar that don't depend on T to INonGenericBar . C# 中唯一的解决方案是将IBar所有不依赖于T的成员重构移动到INonGenericBar

As per my understanding of the .NET CLR: if any other CLR language wants to support this feature they would have to also implement this via some kind of reflection hack because the CLR itself does not support runtime references to generic objects without type parameters (I might be wrong!)根据我对 .NET CLR 的理解:如果任何其他 CLR 语言想要支持此功能,他们也必须通过某种反射 hack 来实现这一点,因为 CLR 本身不支持对没有类型参数的泛型对象的运行时引用(我可能是错的!)

UPDATE!更新!

Apparently Microsoft is aware of requests for support for "wildcard generics" and this GitHub issue is tracking the task - but don't expect this to be implemented for years - considering it took 54 years ( from Tony Hoare's 1965 invention of the null reference to C# 8.0's implementation of non-null reference types) so don't hold your breath.显然,微软知道对“通配符泛型”的支持请求,这个 GitHub 问题正在跟踪任务 - 但不要指望这会实施多年- 考虑到它花了54 年从 Tony Hoare 1965 年发明的空引用到C# 8.0 的非空引用类型的实现)所以不要屏住呼吸。


1 This is definitely a design mistake of the C# language and/or the .NET CLR because it effectively breaks generic inheritance (ie each generic type Dog<T> may need a non-generic parent Dog , but if you have a generic child SamoyedDog<T> , then that too may need a non-generic parent SamoyedDog , but C# and the .NET CLR will not allow SamoyedDog<T> to derive from both SamoyedDog and Dog<T> . 1这绝对是 C# 语言和/或 .NET CLR 的设计错误,因为它有效地破坏了泛型继承(即每个泛型类型Dog<T>可能需要一个非泛型父Dog ,但如果您有一个泛型子SamoyedDog<T> ,那么它也可能需要一个非泛型的父SamoyedDog ,但 C# 和 .NET CLR 将不允许SamoyedDog<T>SamoyedDogDog<T>派生。

2 I consider this ironic[3] because the whole point of reified generics is to have "first-class" generics instead of Java's second-class generics that only matter at compile-time - it's ironic that the end-result of Java's implementation enables (in this case at least) greater flexibility which is the intended result of first-class reified generics. 2我认为这具有讽刺意味 [3] 因为具体化泛型的全部意义在于拥有“一流”的泛型,而不是只在编译时重要的 Java 的二等泛型——具有讽刺意味的是,Java 实现的最终结果使(至少在这种情况下)更大的灵活性,这是一流的具体泛型的预期结果。 I note (provided this is a CLR limitation) that the .NET CLR and C# could support parameter-less generics in a straightforward manner, but the demand just isn't there because the alternative (ie refactoring) is much simpler and the C#/.NET CLR team decided to spend their efforts on other new features.我注意到(假设这是 CLR 限制).NET CLR 和 C#可以直接支持无参数泛型,但需求并不存在,因为替代方案(即重构)要简单得多,而 C#/ .NET CLR 团队决定将精力花在其他新功能上。

[3] As someone who is British and not American, I take pride in using irony correctly! [3] 作为一个英国人而非美国人,我为正确使用讽刺而感到自豪!

If I understand correctly, you need to make IBar<T> covariant.如果我理解正确,您需要使IBar<T>协变。 After that, you can do this without getting a null:之后,您可以在不获得空值的情况下执行此操作:

var GenericParentBar = myFoo as IBar<object>;

To make IBar<T> covariant, simply add the out modifier in the generic parameter;要使IBar<T>协变,只需在泛型参数中添加out修饰符;

public IBar<out T>
{
    bool isGeneric {get;}
}

Note that after this change, you can't add any methods to IBar that takes a T as a parameter.请注意,在此更改之后,您无法向IBar添加任何将T作为参数的方法。 You can only add methods that return T .您只能添加返回T方法。

To learn more about variance, go to here .要了解有关方差的更多信息,请转到此处

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

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