Преобразование типов с помощью общего списка и интерфейсов в C # - в поисках элегантного решения - PullRequest
1 голос
/ 24 сентября 2010

Возьмите следующий пример (созданный исключительно для демонстрации сути).То, что я пытаюсь сделать, - это изолировать одну часть системы от другой, и я хочу предоставить только определенное подмножество функциональности извне из сборки, одновременно работая с методами полных объектов.

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

Кто-нибудь может предложить элегантное решение этой проблемы?

ОБНОВЛЕНО: На основании комментариев я изменил этот пример, чтобы лучше продемонстрировать проблему,Я тоже в образце сейчас показываю решение, которое у меня сработало ...

    using System.Collections.Generic;

    namespace Test
    {
        public class PeopleManager
        {
            List<Person> people = new List<Person>();

            public PeopleManager()
            {
            }

            public void CreatePeople()
            {               
                people.Add(new Person("Joe", "111 aaa st"));
                people.Add(new Person("Bob", "111 bbb st"));
                people.Add(new Person("Fred", "111 ccc st"));
                people.Add(new Person("Mark", "111 ddd st"));                
            }

            public IList<IName> GetNames()
            {
                /* ERROR
                 * Cannot convert type 'System.Collections.Generic.List<Test.Person>' 
                 * to 'System.Collections.Generic.List<Test.IName>' c:\notes\ConsoleApplication1\Program.cs
                 */

                return (List<IName>) people; // <-- Error at this line

                // Answered my own question, do the following

                return people.ConvertAll(item => (IName)item);
            }
        }

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

        internal class Person : IName
        {
            public Person(string name, string address)
            {
                this.Name = name;
                this.Address = address;
            }

            public string Name
            {
                get;
                set;
            }

            public string Address
            {
                get;
                set;
            }
        }
    }

Ответы [ 5 ]

7 голосов
/ 24 сентября 2010
IList<IName> restricted = people.Cast<IName>().ToList(); 
3 голосов
/ 24 сентября 2010

Person наследуется от IName, но List<Person> не наследуется от List<IName>. Представьте, что это так: вы могли бы привести List<Person> к его суперклассу List<IName>, а затем добавить экземпляр IName, который не был экземпляром Person!

Просто сделайте свой List<Person> a List<IName> - этого должно быть достаточно.

1 голос
/ 24 сентября 2010

Я бы создал класс для переноса одной коллекции (для повышения производительности), а не сделал бы копию, как любое другое решение на странице.

public class CovariantList<TType, TBase> : IList<TBase>
where TType:TBase,class
{
private IList<TType> _innerList;

public int Count
{
get
{
return this._innerList.Count;
}
}

public TBase this[int index]
{
get
{
return this._innerList[index];
}
set
{
TType type = value as TType;
if(type!=null)
{
...
}
}
...
1 голос
/ 24 сентября 2010

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

List<IName> restricted = people.ConvertAll(item => (IName) item); 
0 голосов
/ 22 января 2019
IList<IName> restricted = people.ToList<IName>();

немного короче

IList<IName> restricted = people.Cast<IName>().ToList(); 
...