Вопрос об общем методе.NET

Комментарий на hvd вполне уместен, и это только пример. В SQL, например, я думаю, что было бы более ясным:

where val like 'abc%123%xyz' and
      val not like 'abc%abc%' and
      val not like '%xyz%xyz'

Я предполагаю, что что-то совершенно похожее сделать в других средах.

5
задан Gary Brunton 23 September 2008 в 23:07
поделиться

10 ответов

Наследование не работает то же при использовании дженериков. Как Smashery указывает, даже если TypeA наследовался TypeB, myType <TypeA> не наследовался myType <TypeB>.

По сути, Вы не можете позвонить методу, определенному как MethodA (myType <TypeB> b), ожидая myType <TypeB>, и дать ему myType <TypeA> вместо этого. Рассматриваемые типы должны соответствовать точно. Таким образом следующее не скомпилирует:

myType<TypeA> a; // This should be a myType<TypeB>, even if it contains only TypeA's

public void MethodB(myType<TypeB> b){ /* do stuff */ }

public void Main()
{
  MethodB(a);
}

Таким образом в Вашем случае, необходимо было бы передать в IRepo <ITypeEntity> MethodB, даже если он только содержит DetailTypes. Необходимо было бы сделать некоторое преобразование между двумя. При использовании универсального IList Вы могли бы сделать следующее:

public void MethodA<T>(IList<T> list) where T : ITypeEntity
{
  IList<T> myIList = new List<T>();

  foreach(T item in list)
  {
    myIList.Add(item);
  }

  b.MethodB(myIList);
}

Я надеюсь, что это полезно.

3
ответ дан 13 December 2019 в 22:19
поделиться

Хорошо это компилирует хорошо. Я в основном redifined классы для взятия универсальных параметров. Это может быть в порядке в Вашем контексте.

public interface IRepo<TRepo>
{
}

public interface ITypeEntity
{
}


public class ClassA<T> where T : ITypeEntity
{
    ClassB<T> b = new ClassB<T>();
    public void MethodA(IRepo<T> repo)
    {
        b.MethodB(repo);
    }
}
public class ClassB<T> where T : ITypeEntity
{
    IRepo<T> repo;
    public void MethodB(IRepo<T> repo)
    {
        this.repo = repo;
    }
}
3
ответ дан 13 December 2019 в 22:19
поделиться

Проблемой является хитрая для получения головы вокруг. DetailType может наследоваться ITypeEntity, но не является на самом деле ITypeEntity. Ваша реализация DetailType могла представить другую функциональность, таким образом, DetailType реализует ITypeEntity, но не равен ITypeEntity. Я надеюсь, что это имеет смысл...

2
ответ дан 13 December 2019 в 22:19
поделиться

Я получаю следующую ошибку: не может преобразовать из IRepo <'T> к IRepo <'ITypeEntity>

Вы получаете эту ошибку компиляции потому что IRepo<T> и IRepo<ITypeEntity> не то же самое. Последний является специализацией первого. IRepo<T> универсальное определение типа, где параметр типа T является заполнителем, и IRepo<ITypeEntity> constructured универсальный тип универсального определения типа, где параметр типа T от указан, чтобы быть ITypeEntity.

Я продолжаю думать, что это должно скомпилировать, поскольку я вынуждаю T в MethodA иметь тип ITypeEntity.

where ограничение не помогает здесь, потому что оно только ограничивает тип, для которого можно предусмотреть T на сайтах вызова MethodA.

Вот терминология из документации MSDN (см. Дженерики в Платформе.NET), который может помочь:

  • Универсальным определением типа является класс, структура или объявление интерфейса, которое функционирует как шаблон с заполнителями для типов, которые это может содержать или использовать. Например, Dictionary<<K, V> класс может содержать два типа: ключи и значения. Поскольку это - только шаблон, Вы не можете создать экземпляры класса, структуры или интерфейса, который является универсальным определением типа.

  • Универсальные параметры типа или параметры типа, являются заполнителями в универсальном типе или определении метода. Dictionary<K, V> универсальный тип имеет два параметра типа, K и V, которые представляют типы его ключей и значений.

  • Созданный универсальный тип или созданный тип, является результатом определения типов для универсальных параметров типа универсального определения типа.

  • Общий аргумент типа является любым типом, которым заменяют универсальный параметр типа.

  • Общий термин универсальный тип включает и созданные типы и универсальные определения типа.

  • Ограничения являются границами, установленными для универсальных параметров типа. Например, Вы могли бы ограничить параметр типа типами, которые реализуют IComparer<T> универсальный интерфейс, чтобы гарантировать, что экземпляры типа могут быть заказаны. Можно также ограничить параметры типа к типам, которые имеют конкретный базовый класс, которые имеют конструктора по умолчанию, или которые являются ссылочными типами или оценивают типы. Пользователи универсального типа не могут заменить аргументами типа, которые не удовлетворяют ограничения.

1
ответ дан 13 December 2019 в 22:19
поделиться

Посмотрите вопрос @monoxide

И поскольку я сказал там, проверив ряд Eric Lippert сообщений на контравариантности, и ковариантность для дженериков сделает многое из этого более ясным.

1
ответ дан 13 December 2019 в 22:19
поделиться

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

0
ответ дан 13 December 2019 в 22:19
поделиться

во время компиляции даже при том, что Вы ограничиваете его, компилятор только знает, что T в MethodA является ссылочным типом. это не знает то, что вводит его, вынужден.

0
ответ дан 13 December 2019 в 22:19
поделиться

Это - избыточное использование дженериков, если T может только когда-либо быть экземпляром ITypeEntity, Вы не должны использовать дженерики.

Дженерики для того, когда у Вас есть несколько типов, которые могут быть в чем-то.

0
ответ дан 13 December 2019 в 22:19
поделиться

В контексте обертывания Вашей головы вокруг общих методов позвольте мне давать Вам простую родовую функцию. Это - универсальный эквивалент IIf VB () (Непосредственный, если), который является самостоятельно плохой имитацией тернарного оператора C-стиля (?). Это ни для чего не полезно, так как реальный тернарный оператор лучше, но возможно это поможет Вам понять, как родовая функция создается и в том, какие контексты они должны быть применены.

T IIF<T>(bool Expression, T TruePart, T FalsePart)
{
    return Expression ? TruePart : FalsePart;
}
0
ответ дан 13 December 2019 в 22:19
поделиться

Если B является подклассом A, который не означает это Class<B> подкласс Class<A>. Так, по этой той же причине, если Вы говорите"T ITypeEntity", это не означает это"IRepo<T> IRepo<ITypeEntity>". Вам, возможно, придется записать Ваш собственный метод преобразования, если Вы хотите получить эту работу.

0
ответ дан 13 December 2019 в 22:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: