C # Casting перечислимый для интерфейса - PullRequest
0 голосов
/ 15 января 2019

Я заранее прошу прощения, если подобный вопрос был задан ранее. Если да, то, пожалуйста, направьте меня к нему, так как я не смог найти подходящий ответ.

Ситуация, с которой я сталкиваюсь, требует некоторых сложных махинаций для приобретения набора объектов, которые мне нужно передать в качестве параметров моему методу. Тем не менее, у меня возникают проблемы при попытке привести этот набор объектов удобным способом для моего метода. Это упрощенная версия кода:

public void OnMouseClick(object sender, MouseButtonEventArgs e) {
  var value = (sender as (DataGridCell)).[...].GetValue(context, null);

  var objects = value as ObservableCollection<IViewModelObject>;
  myMethod(objects);
}

public void myMethod(IEnumerable<IViewModelObject> objects) {
  doStuff(objects);
}

public interface IViewModelObject { }
public class ViewModelObject1 : IViewModelObject { }
public class ViewModelObject2 : IViewModelObject { }

В настоящее время объекты всегда равны нулю, поскольку приведение не выполняется. Тем не менее, бросок успешен, если я сделаю

var objects = value as ObservableCollection<ViewModelObject1>;

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

Обратите внимание, что myMethod не нужно знать, какой класс реализации используется, и я, вероятно, мог бы использовать IEnumerable, и это все равно будет работать. К сожалению, актёрский состав тоже не удался.

Полагаю, компилятору не нравится, когда дочерние классы приводятся к их базе, но я чувствую, что есть еще способ добиться аналогичного эффекта. Есть идеи?

1 Ответ

0 голосов
/ 15 января 2019

ObservableCollection<T> является инвариантом, очень похоже на List<T>. Причина, по которой вы получаете null вместо исключения приведения, заключается в том, что вы сбрасываете с object, а не ObservableCollection<T>.

Рассмотрим следующее:

interface IFoo { }
class Foo : IFoo { }

void Main() 
{
    var foo = new ObservableCollection<Foo>();
    object oFoo = foo;

    // The following will compile, but will always be null as the cast fails:
    var nullValue = oFoo as ObservableCollection<IFoo>;
    // The following will throw a compilation error, 
    // as the compiler recognizes the invalid conversion
    var compileError = foo as ObservableCollection<IFoo>;
}

Это было бы хорошо с IEnumerable<T>, поскольку IEnumerable<T> является ковариантным, что похоже на поведение, которое вы ожидали.

Покрывая почему , мы можем разобраться с тем, как:

var foo = new ObservableCollection<Foo>();
var bar = new ObservableCollection<IFoo>(foo as IEnumerable<IFoo>);

Конечно, это копия, а не актерский состав, но я не верю, что вы сможете обойти это.

Поскольку, похоже, вам просто нужно представление IEnumerable в любом случае, вы можете просто пропустить приведенное выше и изменить свой код так, чтобы он выглядел следующим образом:

var objects = value as IEnumerable<IViewModelObject>;
myMethod(objects);
...