简体   繁体   中英

C# Casting enumerable to interface

I apologize in advance if a similar question has been asked before. If so, please direct me to it, as I was unable to find a suitable answer.

The situation I am dealing with requires some complex shenanigans to acquire a set of objects, that I need to pass as parameters to my method. However, I am having issues while attempting to cast this set of objects in a useable way to my method. This is a simplified version of the code:

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 { }

Currently, objects is always null, as the cast fails. However, the cast succeeds if I do

var objects = value as ObservableCollection<ViewModelObject1>;

But this renders me unable to use the interface in my method, and god knows I have a lot classes implementing that interface and would like to avoid having to write statements for all of them.

Note that myMethod does not need to know what implementing class is being used, and I could probably use an IEnumerable and that would still work. Unfortunately the cast fails there too.

I'm guessing the compiler doesn't like child classes being cast towards their base, but I feel like therer should still be a way to accomplish a similar effect. Any ideas?

ObservableCollection<T> is invariant, much like List<T> . The reason you're getting back null instead of a casting exception is because you're casting down from object , rather than ObservableCollection<T> .

Consider the following:

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>;
}

This would be fine with an IEnumerable<T> , as IEnumerable<T> is covariant, which seems like the behavior you were expecting.

Having covered the why , we can deal with the how:

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

Of course, this is a copy, not a cast, but I don't believe you'll be able to get around that.

Since it looks like you just need the IEnumerable representation either way, you can likely just skip the above and alter your code to look like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM