简体   繁体   中英

Type conversion with Generic List and Interfaces in C# - Looking for an elegant solution

Take the following example (created purely to demonstrate the point). What I am trying to do is isolate one part of the system from another and only want to expose a specific subset of the functionality externally from the assembly while internally working against the full objects methods.

This code compiles, but I get an invalid cast exception at runtime. It feels like this should work but unfortunately it does not.

Can anybody suggest an elegant solution to this problem?

UPDATED: Based on comments I have changed this example to better demonstrate the issue, I also in the sample now show the solution that worked for me...

    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;
            }
        }
    }
IList<IName> restricted = people.Cast<IName>().ToList(); 

Person inherits from IName but List<Person> does not inherit from List<IName> . Imagine if it did: you'd be able to cast a List<Person> to its superclass, List<IName> , then add an instance of IName that was not an instance of Person !

Just make your List<Person> a List<IName> --that should be sufficient.

Answered my own question but thought I would post in case anybody else runs into this in the future. At the line where the error occurs you can actually do this which is pretty nifty:

List<IName> restricted = people.ConvertAll(item => (IName) item); 

I would create a class to wrap the one collection (for performance) rather than make a copy like every other solution on the page.

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)
{
...
}
}
...
IList<IName> restricted = people.ToList<IName>();

短于

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

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