类型参数“T”与外部类型“…”中的类型参数同名

public abstract class EntityBase { ... } public interface IFoobar { void Foo(int x) where T : EntityBase, new(); } public interface IFoobar where T : EntityBase, new() { void Foo(int x); } public class Foobar : IFoobar, IFoobar where T : EntityBase, new() { public void Foo(int x) { ... } void IFoobar.Foo(int x) { Foo(x); } } 

我收到编译器警告: Type parameter 'T' has the same name as the type parameter from outer type '...'

我尝试过: void IFoobar.Foo(int x) { Foo(x); } 然而,我无法保证U和T是相同的。 Foobar类的实现方式,它们是相同的非常重要。

我也尝试过: void IFoobar.Foo(int x) where U : T { Foo(x); } 但是,这并不能保证U和T相等,并且它不允许我重新定义约束,因为它是在接口上定义的。

你可以做以下两件事之一:

  1. 忽略警告并使两种类型T.
  2. 执行运行时检查并抛出exception:

     if (typeof(T) != typeof(U)) throw Exception("Not the same type"); 

正如其他人所说,也许您需要重新思考设计界面的方式。

最大的问题是您的接口定义不明确,并且与您的代码意图不符。

如果您的T在界面上不公开,那么外部代码甚至不必知道有T 您需要创建接收或返回T ,或者具有类型T某些属性,或者您应该完全摆脱T ,并使您的接口非generics。

一旦你坚持下去,为什么你不需要两个不同的接口就应该变得更加明显,你不再需要调和它们。

如果事实certificate你确实需要一个采用T和非T版本的版本,那么更惯用的方法是传递object而不是T

 public interface IFoo { void DoSomething(object o); object DoSomethingElse(); } public interface IFoo { void DoSomething(T item); T DoSomethingElse(); } 

有关此示例,请参阅IEnumerableICollectionIList等接口。

但要仔细考虑 。 最后的设计折衷(同时具有通用版本和对象版本)总会留下一些需要。

你将牺牲其中一个:

  • 直接传达设计合同的良好界面设计(如果在传入错误类型时抛出exception或执行no-op)
  • 键入安全性,减少与之相关的错误(如果您正确操作任何旧对象)

试一试

 void IFoobar.Foo(int x) { Foo(x); } 

当然,这仍然不能保证UT相同。 你不能在编译时强制执行,因为当你实现一个接口时,你必须遵循它的规则 – 而且IFoobar没有对Foo施加这样的限制,如果你这样做,你就不会更长的是实现界面(根据定义,因为你更严格,但你声称你不是)。

你可以尝试在运行时检查它,虽然这有点“作弊”(因为你不是真的符合接口)。