简体   繁体   中英

IList<T>, IEnumerable<T> and ObservableCollection<T>

I have two classes defined like

public class PostleitzahlList : ObservableCollection<Postleitzahl> {
}

public class Postleitzahl : IPostleitzahl {
}

Now I have a Service-Class which contains

PostleitzahlList _postleitzahlList;

This Serviceclass has also to implement a Property of a Service-Interface which returns _postleitzahlList - but this Interface only knows IPostleitzahl - it doesn't know PostleitzahlList or Postleitzahl . this Property should be used for Binding in WPF.

I am trying now to declare and implement this Property. I have tried

    public ObservableCollection<IPostleitzahl> PostleitzahlList {
        get { return this._postleitzahlList; }
    }

and

    public IList<IPostleitzahl> PostleitzahlList {
        get { return this._postleitzahlList; }
    }

But both does not work. The fallowing seems to work:

    public IEnumerable<IPostleitzahl> PostleitzahlList {
        get { return this._postleitzahlList; }
    }

I ask me now 1. why does the first and second try not working? 2. what is the best solution to solve this?

The problem is with covariance. An ObservableCollection<Postleitzahl> isn't an ObservableCollection<IPostleitzahl> , and ditto with lists. Here's an example of why not:

ObservableCollection<string> strings = new ObservableCollection<string>();

// This is invalid, but it's what you're trying to do, effectively.
ObservableCollection<object> objects = strings;

// This would have to work... it's fine...
objects.Add(new object());

// And this should be fine too...
string x = strings[0];

... but as you can see, you're now trying to fetch a non-string reference and store it in a string variable. The only viable outcome would be an execution-time failure... and half the point of generics is to push error detection to compile-time .

Now IEnumerable<T> is covariant in T because you can't add any items via it - that makes it safe to apply that sort of conversion:

// There's nothing you can do to violate type safety here...
Observable<string> strings = new ObservableCollection<string>();
IEnumerable<object> objects = strings;

For more information, read up on covariance and contravariance in generics in MSDN .

Do you need the IPostleitzahl interface? If you just exposed the properties via ObservableCollection<Postleitzahl> or IList<Postleitzahl> it would be fine. Alternatively, you could change your variable to be an ObservableCollection<IPostleitzahl> and just happen to populate it by creating Postleitzahl instances.

can you change PostleitzahlList to

public class PostleitzahlList : ObservableCollection<IPostleitzahl> {
}

with elementtype IPostleitzahl instead of Postleitzahl ?

for explanation see @jon skeet answer

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