类型参数“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相等,并且它不允许我重新定义约束,因为它是在接口上定义的。
你可以做以下两件事之一:
- 忽略警告并使两种类型T.
-
执行运行时检查并抛出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(); }
有关此示例,请参阅IEnumerable
, ICollection
, IList
等接口。
但要仔细考虑 。 最后的设计折衷(同时具有通用版本和对象版本)总会留下一些需要。
你将牺牲其中一个:
- 直接传达设计合同的良好界面设计(如果在传入错误类型时抛出exception或执行no-op)
- 键入安全性,减少与之相关的错误(如果您正确操作任何旧对象)
试一试
void IFoobar.Foo(int x) { Foo(x); }
当然,这仍然不能保证U
与T
相同。 你不能在编译时强制执行,因为当你实现一个接口时,你必须遵循它的规则 – 而且IFoobar
没有对Foo
施加这样的限制,如果你这样做,你就不会更长的是实现界面(根据定义,因为你更严格,但你声称你不是)。
你可以尝试在运行时检查它,虽然这有点“作弊”(因为你不是真的符合接口)。