Не может реализовать элемент интерфейса, потому что у него нет соответствующего типа возврата List <IInterface> '

У меня есть интерфейс IChild и IParent. IParent имеет a List<IChild>.

Почему класс, реализующий IParent, не может иметь список классов, реализующих IChild Каков общий способ достижения этого?

public interface IChild
{ 
}  

public interface IParent
{  
    List<IChild> a { get; set; }
} 

public class ChildA : IChild
{ 
} 

public class ChildB : IChild
{ 
} 

public class ParentA : IParent
{ 
    public List<ChildA> a { get; set; }
}

public class ParentB : IParent
{ 
    public List<ChildB> a { get; set; }
}

Выдает следующую ошибку:

`MyApp.Data.ParentA` does not implement interface member `MyApp.Data.IParent.a`.
`MyApp.Data.ParentA.a` cannot implement `MyApp.Data.IParent.a` because 
it does not have the matching return type of 
`System.Collections.Generic.List<MyApp.Data.IChild>`

Ответ 1

Сделать общий IParent:

public interface IChild
{
}

public interface IParent<TChild> where TChild : IChild
{
    List<TChild> a { get; set; } 
}

public class ChildA : IChild {  }   

public class ChildB : IChild {  }   

public class ParentA : IParent<ChildA>
{
    public List<ChildA> a { get; set; }
}

public class ParentB : IParent<ChildB>
{
    public List<ChildB> a { get; set; }
}

Ответ 2

Вам нужно, чтобы классы возвращали List<IChild>:

public class ParentA : IParent
{ 
    public List<IChild> a { get; set; }
}

public class ParentB : IParent
{ 
    public List<IChild> a { get; set; }
}

Ответ 3

Коллекция IChild не может быть неявно преобразована в коллекцию своего дочернего типа

Измените тип возврата IParent.a на List<ChildA> ИЛИ изменить объявление свойства на ParentA и ParentB на public List<IChild> a { get; set; }. Я рекомендую последнее, так как я думаю, что вы, скорее всего, собираетесь.

Ответ 4

Реализация может возвращать только список IChild следующим образом:

public interface IChild
{
}

public interface IParent
{
    List<IChild> Children { get; set; }
}

public class ChildA : IChild
{
}

public class ChildB : IChild
{
}

public class ParentA : IParent
{

    public List<IChild> Children
    {
        get;
        set;

    }
}

public class ParentB : IParent
{
    public List<IChild> Children
    {
        get;
        set;
    }
}

Ответ 5

Если вы используете С# 4 или новее, вы можете сделать это:

public interface IChild
{ 
}  

public interface IParent
{  
    IEnumerable<IChild> a { get; set; }
} 

public class ChildA : IChild
{ 
} 

public class ChildB : IChild
{ 
} 

public class ParentA : IParent
{ 
    private IEnumerable<IChild> _a;
    public IEnumerable<IChild> a
    { 
        get { return new List<ChildA>(); }
        set { _a = value; }
    }
}

public class ParentB : IParent
{ 
    private IEnumerable<IChild> _b;
    public IEnumerable<IChild> b
    { 
        get { return new List<ChildB>(); }
        set { _b = value; }
    }
}

Ответ 6

У меня было аналогичное требование, когда у меня было два разных метода, которые работали на двух разных классах, но имели одинаковую логику в нем для свойств, которые являются общими для обоих классов.

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

namespace OOPS.Interfaces
{
    using System.Collections.Generic;

    public interface IBanner
    {
        string Name { get; set; }
    }

    public interface IBannerContent<T> where T : IBanner
    {
        List<T> Banners { get; set; }
    }
}

Простая модель.

namespace OOPS.Simple
{
    using Interfaces;
    using System.Collections.Generic;

    public class Banner : IBanner
    {
        public string Name { get; set; }
    }

    public class BannerContent : IBannerContent<Banner>
    {
        public List<Banner> Banners { get; set; }
    }
}

Комплексная модель.

namespace OOPS.Complex
{
    using Interfaces;
    using System.Collections.Generic;

    public class Banner : IBanner
    {
        public string Name { get; set; }

        public string Description { get; set; }
    }

    public class BannerContent : IBannerContent<Banner>
    {
        public List<Banner> Banners { get; set; }
    }
}

Общая бизнес-логика и вызов образца. Ключевая часть здесь заключается в использовании предложения where для ограничения типа, такого как where T : IBanner, вплоть до метода, который мы хотим, чтобы он был общим.

namespace OOPS
{
    using Interfaces;
    using System;
    using System.Collections.Generic;

    public class BusinessLogic
    {
        public void Print<T>(IBannerContent<T> bannerContent) where T : IBanner
        {
            foreach (var item in bannerContent.Banners)
            {
                Console.WriteLine(item.Name);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var banner1 = new Simple.BannerContent
            {
                Banners = new List<Simple.Banner>
                {
                    new Simple.Banner { Name = "Banner 1" },
                    new Simple.Banner { Name = "Banner 2" }
                }
            };

            var banner2 = new Complex.BannerContent
            {
                Banners = new List<Complex.Banner>
                {
                    new Complex.Banner { Name = "Banner 3", Description = "Test Banner" },
                    new Complex.Banner { Name = "Banner 4", Description = "Design Banner" }
                }
            };

            var business = new BusinessLogic();
            business.Print(banner1);
            business.Print(banner2);
            Console.ReadLine();
        }
    }
}