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

时间:2011-07-19 00:18:46

标签: c# generics interface constraints explicit-interface

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相等,并且它不允许我重新定义约束,因为它是在接口上定义的。

3 个答案:

答案 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(); } IEnumerableICollection等界面。

但请仔细考虑。最后的设计折衷(同时具有通用版本和对象版本)总是有所不足。

你会牺牲其中一个:

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

答案 1 :(得分:9)

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

  1. 忽略警告并使两种类型都为T。
  2. 进行运行时检查并抛出异常:

    if (typeof(T) != typeof(U)) throw Exception("Not the same type");
    
  3. 正如其他人所说,也许您需要重新考虑设计界面的方式。

答案 2 :(得分:3)

试试

void IFoobar.Foo<U>(int x) { Foo(x); }

当然,这仍然不能保证UT相同。您无法在编译时强制执行此操作,因为当您实施界面时,必须遵循其规则 - 并且IFoobar不会对Foo<T>施加了这样的限制,如果你这样做,你将不再实现界面(根据定义,因为你更严格,但你声称你不是)。

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