public abstract class EntityBase { ... }
public interface IFoobar
{
void Foo<T>(int x)
where T : EntityBase, new();
}
public interface IFoobar<T>
where T : EntityBase, new()
{
void Foo(int x);
}
public class Foobar<T> : IFoobar, IFoobar<T>
where T : EntityBase, new()
{
public void Foo(int x) { ... }
void IFoobar.Foo<T>(int x) { Foo(x); }
}
我收到编译器警告:Type parameter 'T' has the same name as the type parameter from outer type '...'
我尝试过:void IFoobar.Foo<U>(int x) { Foo(x); }
但是我无法保证U和T是相同的。 Foobar类的实现方式,它们是相同的非常重要。
我也尝试过:void IFoobar.Foo<U>(int x) where U : T { Foo(x); }
,但这并不保证U和T相等,并且它不允许我重新定义约束,因为它是在接口上定义的。
答案 0 :(得分:12)
最大的问题是您的界面定义不明确,与您的代码意图不符。
如果您的T
未在界面上公开显示,则外部代码甚至不必知道有T
。您需要创建接收或返回T
的方法,或者具有类型T
的某些属性,或者您应该完全摆脱T
,并使您的接口不是通用的。
一旦你坚持下去,为什么你在这里不需要两个不同的界面就应该变得更加明显,你不应该再调和它们了。
如果事实证明你做需要的版本需要T
和非T版本,那么更常用的方法是传递{{1}而不是object
:
T
有关此示例,请参阅public interface IFoo
{
void DoSomething(object o);
object DoSomethingElse();
}
public interface IFoo<T>
{
void DoSomething(T item);
T DoSomethingElse();
}
,IEnumerable
,ICollection
等界面。
但请仔细考虑。最后的设计折衷(同时具有通用版本和对象版本)总是有所不足。
你会牺牲其中一个:
答案 1 :(得分:9)
你可以做以下两件事之一:
进行运行时检查并抛出异常:
if (typeof(T) != typeof(U)) throw Exception("Not the same type");
正如其他人所说,也许您需要重新考虑设计界面的方式。
答案 2 :(得分:3)
试试
void IFoobar.Foo<U>(int x) { Foo(x); }
当然,这仍然不能保证U
与T
相同。您无法在编译时强制执行此操作,因为当您实施界面时,必须遵循其规则 - 并且IFoobar
不会对Foo<T>
施加了这样的限制,如果你这样做,你将不再实现界面(根据定义,因为你更严格,但你声称你不是)。
您可以尝试在运行时检查它,虽然这有点“作弊”(因为您之前并不真正符合接口)。