Why can't I use a compatible concrete type when implementing an interface

前端 未结 3 1085
深忆病人
深忆病人 2020-12-15 09:45

I would like to be able to do something like this :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
          


        
相关标签:
3条回答
  • 2020-12-15 09:55

    You're not going to be able to use a concrete type unless you do it behind the scenes. The problem is that you can both Get and Set the Property.

    Your interface specifies that the property is of type IEnumerable<int>. HashSet<int> implements IEnumerable<int>. That means the following should work just fine:

    IFoo instance = new Bar();
    instance.integers = new HashSet<int>();
    

    But since you're trying to implement the interface using the concrete type List<int>, there's no way that assignment can work.

    The easiest fix, assuming you don't constantly need to re-assign the collection, would be to only specify a getter for the collection:

    public interface IFoo
    {
        IEnumerable<int> Integers { get; }
    }
    
    public class Bar
    {
        public List<int> Integers { get; private set; }
    
        public Bar(List<int> list)
        {
            Integers = list;
        }
    }
    
    0 讨论(0)
  • 2020-12-15 10:01

    This is a Type Covariance/Contravariance issue (see http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#C.23 ).

    There's a workaround: use explicit interfaces, like so:

    public class Bar : IFoo {
    
        private IList<int> _integers;
    
        IEnumerable<int> IFoo.integers {
            get { return _integers };
            set { _integers = value as IList<int>; }
        }
    
        public IList<int> integers {
            get { return _integers; }
            set { _integers = vale; }
        }
    }
    

    Note that integers should be TitleCased to conform to .NET's guidelines.

    Hopefully you can see the problem in the code above: IList<int> is compatible with IEnumerable<int> only for the accessor, but not for setting. What happens if someone calls IFoo.integers = new Qux<int>() (where Qux : IEnumerable<int> but not Qux : IList<int>).

    0 讨论(0)
  • 2020-12-15 10:07

    Although List implements IEnumerable that's not the way interfaces work. The interface specifies exactly which types need to be exposed for properties. If you created a generic interface like

    public interface IFoo<T> where T : IEnumerable<int>
    {
        T integers { get; set; }
    }
    

    You could then use IFoo<List<int>> to implement it in the way you expect.

    0 讨论(0)
提交回复
热议问题