Проблема приведения в обобщенном методе C # - PullRequest
2 голосов
/ 13 ноября 2008

У меня возникли проблемы с общим методом, который я пишу. Имеет следующую подпись:

public static ThingCollection<T> GetThings<T>(...) where T : Thing

Есть несколько классов; ThingA, ThingB и ThingC, которые наследуются от Thing; и я хочу, чтобы в методе было что-то вроде этого.

var things = new ThingCollection<T>();

if (typeof(T) == typeof(Thing))
  foreach (var item in someCollection)
    things.Add((T)new Thing(...));
else if (typeof(T) == typeof(ThingA))
  foreach (var item in someCollection)
    things.Add((T)new ThingA(...));
else if (typeof(T) == typeof(ThingB))
  foreach (var item in someCollection)
    things.Add((T)new ThingB(...));
else if (typeof(T) == typeof(ThingC))
  foreach (var item in someCollection)
    things.Add((T)new ThingC(...));
else
  throw new Exception("Cannot return things of type " + typeof(T).ToString());

return things;

Проблема в том, что я получаю лучшее совпадение перегруженного метода с ошибочными аргументами ошибка, если я не приведу новые объекты. Добавление приведений T, как показано выше, подходит для нового Thing (), но сообщает Невозможно преобразовать тип 'ThingA' в 'T' для других новых вызовов. Intellisense означает, что T - это вещь, но я не понимаю, почему я не могу привести другие объекты к вещи, поскольку они наследуются от нее.

Возможно, это не правильный способ делать то, что я пытаюсь сделать. Я на правильном пути? Возможно, пропущен какой-то маленький нюанс, или я должен заниматься чем-то другим полностью?

Ответы [ 4 ]

7 голосов
/ 13 ноября 2008

Я не понимаю, что вы пытаетесь сделать с этим кодом.

Если вы хотите создать коллекцию вещей, в которую вы можете добавить любой тип класса, производного от Thing, ThingCollection не должен иметь Typename: он должен быть коллекцией для конкретных типов.

Например, реализация ThingCollection следующим образом:

public class ThingCollection : List<Thing> {}

теперь вы можете сделать

ThingCollection tc = new ThingCollection();
tc.Add(new ThingA());
tc.Add(new ThingB());
tc.Add(new ThingC());

Предполагая, конечно, что ThingA, ThingB и ThingC наследуются от Thing.

Или, может быть, вы хотите фильтровать производные типы вещей с помощью GetThings (), т. Е. Хотите, чтобы вызов GetThings () возвращал коллекцию ThingCollection.

3 голосов
/ 13 ноября 2008

В основном, я думаю, этот фрагмент кода имеет плохой дизайн. Если вы добавите класс «ThingD», вам понадобится изменить другую часть кода для ясного поведения. Вы должны использовать что-то вроде:

public static ThingCollection<T> GetThings<T>(...) where T : Thing, new()
...
...
T item = new T();
item.Something = Whatever();

Или вы можете реализовать интерфейс "ICloneable" в классе Thing.

3 голосов
/ 13 ноября 2008

Код нарушает принцип подстановки Лискова, поскольку он пытается проверить тип T перед его использованием.

Чтобы избежать этого, вы можете использовать комбинацию словарь / стратегия или шаблон посетителя.

Если T - это ThingB, то приведение (T) к ThingA недопустимо, поэтому код на самом деле неправильный.

2 голосов
/ 13 ноября 2008

Если они используют общий интерфейс (IThing), вы должны быть в состоянии привести его к этому.

...