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 = ad开发者_运维知识库dress;
}
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>();
little shorter than
IList<IName> restricted = people.Cast<IName>().ToList();
精彩评论