Параметр типа 'T' имеет то же имя, что и параметр типа из внешнего типа '...' - PullRequest
16 голосов
/ 19 июля 2011
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 ]

12 голосов
/ 19 июля 2011

Самая большая проблема в том, что ваши интерфейсы не определены должным образом и не соответствуют цели вашего кода.

Если ваш T не виден в интерфейсе, то внешний код недаже нужно знать, что есть T.Вам нужно либо создать методы, которые получают или возвращать T, либо иметь какое-либо свойство типа T, либо вы просто должны полностью избавиться от T и сделать свои интерфейсы не универсальными.

Как только вы подтвердите это, должно стать более очевидным, почему вам не нужны два разных интерфейса, и вам больше не нужно их согласовывать.

Если окажется, что вы делаете нужна версия, которая принимает T, и версия не-T, тогда более идиотский способ сделать это - обойти object вместо T:

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

public interface IFoo<T>
{
    void DoSomething(T item);
    T DoSomethingElse();
}

См. интерфейсы, такие как *Примеры 1020 *, ICollection, IList и т. Д.

Но внимательно рассмотрим .Этот последний компромисс дизайна (имеющий как универсальную, так и объектную версию) всегда оставляет желать лучшего.

Вы пожертвуете одним из них:

  • Хороший дизайн интерфейса, который напрямую связываетконтракт на разработку (если вы генерируете исключения или не выполняете операции, когда передается неправильный тип)
  • Безопасность типов и сокращение ошибок, связанных с этим (если вы правильно работаете с любым старым объектом)
9 голосов
/ 19 июля 2011

Вы можете сделать одну из двух вещей:

  1. Игнорировать предупреждение и сделать оба типа T.
  2. Выполните проверку во время выполнения и сгенерируйте исключение:

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

Как уже говорили другие, возможно, вам нужно переосмыслить способ проектирования интерфейсов.

3 голосов
/ 19 июля 2011

Просто попробуйте

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

Конечно, это еще не гарантирует, что U совпадает с T.Вы не можете применить это во время компиляции, потому что при реализации интерфейса вы должны следовать его правилам - а IFoobar не накладывает такого ограниченияна Foo<T>, и если вы это сделаете, вы больше не будете реализовывать интерфейс (по определению, поскольку вы строже, и при этом вы заявляете, что это не так).

Вы можете попробоватьвместо этого, проверяя его во время выполнения, хотя это несколько «обманывает» (так как вы на самом деле тоже не соответствует интерфейсу).

...