Polymorphism. What will I not get?

I have a problem with polymorphism in C #. I have an object that implements an interface, however I cannot present a collection of objects as a set of interfaces. It flies in the face of my understanding of polymorphism. So I was wondering where I was wrong.

[TestFixture] class Tester { [Test] public void Polymorphism() { var list = new List<Foo> {new Foo {Name = "Item"}}; Assert.That(list, Is.InstanceOf<IList>()); Assert.That(list[0], Is.InstanceOf<Foo>()); Assert.That(list[0], Is.InstanceOf<IBar>()); // why are the rest true but this false? Assert.That(list, Is.InstanceOf<IList<IBar>>()); } } internal interface IBar { } internal class Foo : IBar { public string Name { get; set; } } 
+4
source share
3 answers

This is a matter of dispersion, not polymorphism.

If List-of-Foo was also IList-of-IBar, the following will work:

 class Another : IBar {} IList<IBar> list = new List<Foo>(); list.Add(new Another()); 

Then we added Another to the Foo list. This is mistake. The compiler stopped your error.

Note that recent versions of /.net compilers support dispersion through "in" / "out". Thus, List-of-Foo is great for IEnumerable-of-IBar. Because it is guaranteed to return Foo (not accept them), and all Foo are also IBar - therefore, it is safe.

+4
source

I will also abandon my two cents. The problem you are facing can be better understood if you increase your understanding of covariance and contravariance (see http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance -faq.aspx ).

I modified your code a bit and came up with this working testing method:

 public void TestMethod1() { var list = new List<Foo> { new Foo { Name = "Item" } }; Assert.IsNotNull(list as IList); Assert.IsNotNull(list[0] as Foo); Assert.IsNotNull(list[0] as IBar); Assert.IsNotNull(list as IList<Foo>); Assert.IsNotNull((IList<Foo>)list); } 
+1
source
 var list = new List<Foo> 

A list is a List<Foo> , not a List<IBar> . Even if Foo implements IBar , the list itself is still a Foo list.

Thus, you cannot add any other type that implements IBar to this list. Only Foo 's, which is obviously Foo or any type that also derives from Foo , as it will also be Foo . I told Foo too much.

If you want to add any type that implements IBar , then you can make the list a collection of IBar instead:

 var list = new List<IBar> { new Foo { Name = "Item" } }; 
0
source

Source: https://habr.com/ru/post/1492579/


All Articles