public interface IDic
{
int Id { get; set; }
string Name { get; set; }
}
public class Client : IDic
{
}
How can I cast List<Client> to List<IDic>?
You can't cast it (preserving reference identity) - that would be unsafe. For example:
public interface IFruit {}
public class Apple : IFruit {}
public class Banana : IFruit {}
...
List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());
// Eek - it's a banana!
Apple apple = apples[0];
Now you can convert a List<Apple> to an IEnumerable<IFruit> in .NET 4 / C# 4 due to covariance, but if you want a List<IFruit> you'd have to create a new list. For example:
// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();
// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();
But this is not the same as casting the original list - because now there are two separate lists. This is safe, but you need to understand that changes made to one list won't be seen in the other list. (Modifications to the objects that the lists refer to will be seen, of course.)
A Cast iterator and .ToList():
List<IDic> casted = input.Cast<IDic>().ToList() will do the trick.
Originally I said covariance would work - but as Jon has rightly pointed out; no it won't!
And originally I also stupidly left off the ToList() call
I too had this problem and after reading Jon Skeet's answer I modified my code from using List<T> to use IEnumerable<T>. Although this does not answer the OP's original question of How can I cast List<Client> to List<IDic>, it does avoid the need to do so and thus may be helpful to others who encounter this issue. This of course assumes that the code that requires the use of List<IDic> is under your control.
E.g.:
public void ProcessIDic(IEnumerable<IDic> sequence)
{
// Implementation
}
Instead of:
public void ProcessIDic(List<IDic> list)
{
// Implementation
}
If you can use LINQ then you can do this...
List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();
Its only possible by creating new List<IDic> and transfering all elements.
In .Net 3.5, you can do the following:
List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());
The constructor for List in this case takes an IEnumerable.
list though is only convertible to IEnumerable. Even though myObj may be convertible to ISomeInterface the type IEnumerable is not convertible to IEnumerable.
OfType
You can try something like:
using (var dbContext = YourDatabaseContext())
{
var list = dbContext.Clients.Where(x => x.Happy)
.OfType<IDic>()
.ToList();
}
See https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype
If you want to process the original list without creating a separated reference, you could define the generic method like this:
public void DoIterate<T>(List<T> myCollection) where T : IDic
{
foreach (T item in myCollection)
{
//update a property of interface
item.Name = "new Name";
}
}
Calling this method above to process the list without having to cast specific object to interface:
List<Client> clients = new List<Client>();
DoIterate(clients);
If you don't need to modify the contents of the original list, you can implicitly convert a List into a IReadOnlyList which will let you iterate over it's contents as IDics without creating a new list.
List<Client> myClients = new List<Client>();
myClients.Add(new Client());
IReadOnlyList<IDic> castedClients = myClients;
foreach(IDic val in castedClients)
{
//do something;
}
The conversion can also occur while simply returning the list like so :
public IReadOnlyList<IDic> getClientsAsIDic()
{
return myClients;
}
Related
In C#, I want to take an array of Type "T" where I know "T" supports the interface "IMyInterface" and:
Cast it as array of "IMyinterface"
Call a method on that array that will filter the list
Cast it back to the original type T list.
1 and 2 above work fine, but I am running into issues on step #3.
Here is my code:
IEnumerable<IMyInterface> castedArray = originalTypedArray as IEnumerable<IMyInterface>;
if (castedArray != null)
{
var filteredArray = castedArray.Where(r => r.Ids.Contains(MyId)).ToList();
IEnumerable<T> castedBackToOriginalTypeArray = filteredArray as IEnumerable<T>;
if (castedBackToOriginalTypeArray == null)
{
current = new List<T>();
}
else
{
current = castedBackArray;
}
// I need to cast back, because only my Type T has the .Id property
List<int> ids = current.Select(r => r.Id).ToList();
}
The issue is on this line:
IEnumerable<T> castedBackToOriginalTypeArray = filteredArray as IEnumerable<T>;
That always seem to return null (instead of the filtered array cast back to IEnumerable<T>.
Any suggestions here for what I might be doing wrong and how to correct cast an array of an interface back into an array of type T?
This works for me:
public class A : IA {
}
public interface IA {
}
List<A> l = new List<A> { new A(), new A(), new A() };
IEnumerable<IA> ias = l.Cast<IA>();
IEnumerable<A> aTypes = ias.Cast<A>();
Either you don't need to cast it to IEnumerable<IMyInterface>, or the runtime has correctly prevented you from writing buggy code.
Let's take a smaller example:
void SomeMethod<T>(IEnumerable<T> originalTypedArray, int MyId)
where T : class, IMyInterface
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is important
{
if (originalTypedArray != null)
{
var filteredArray = originalTypedArray.Where(r => r.Ids.Contains(MyId));
// No need to cast to `IEnumerable<T>` here - we already have ensured covariance
// is valid in our generic type constraint
DoSomethingExpectingIEnumerableOfIMyInterface(filteredArray);
}
}
void DoSomethingExpectingIEnumerableOfIMyInterface(IEnumerable<IMyInterface> src)
{
foreach (var thing in src)
{
}
}
However, if you're not getting the collection as IEnumerable<T>, then the runtime is correctly failing the cast:
void SomeMethod<T>(IEnumerable<IMyInterface> originalTypedArray, int MyId)
We could give it a bunch of IEnumerable<Apple> assuming Apple : IMyInterface. Then you try to cast it to IEnumerable<T> where T = Banana and boom, code broken.
My friend is trying to create a utility function that is given some Type and in that function it creates a generic List of that type. We're having trouble creating that list:
public static List<T> GetQueryResult(string xpathQuery, Type itemType) {
// this line does not work:
List<itemType> lst = new List<itemType>();
return lst;
}
Are there any easy solutions to this?
UPDATE:
Is there any way to basically do this???
List<T> lst = new List<T>();
foreach (Sitecore.Data.Items.Item i in items) {
lst.Add(new T(i));
}
public static List<T> GetQueryResult<T>(string xpathQuery/*, Type itemType you don't need this because you specified the Type with T*/) {
// this line works now:
List<T> lst = new List<T>();
return lst;
}
Then you would call the method like so:
List<int> results = GetQueryResult<int>("xpathQuery");
Edit:
Are you wanting to do something like this?
List<YourType> lst = items.Select<Sitecore.Data.Items.Item, YourType>(
siteCoreItem => new YourType()
{
PropertyA = siteCoreItem.PropertyA,
}
);
If YourType inherrits from Sitecore.Data.Items.Item you can use Cast:
List<YourType> list = items.Cast<YourType>();
Define that method like this:
public static List<T> GetQueryResult<T>(string xpathQuery)
{
List<T> lst = new List<T>();
// do stuff
return lst;
}
and call it like this:
List<SomeType> items = SomeClass.GetQueryResult<SomeType>("query");
It is possible using reflection, for example:
var type = typeof(int); // var type = itemType : put this line to fit the method
var genericListType = typeof(List<>).MakeGenericType(type);
var genericList = Activator.CreateInstance(genericListType);
Assert.IsTrue(genericList is List<int>);
In your example, ehere do you get T from that you use in the return type? Maybe there is no need to use here reflection.
If you do not get T as generic argument then you cannot return the List as generic List and the method will have to return a non generic type (like IList instead of List).
While Elisha's answer shows you how you can create a constructed generic type from a Type instance, it's not going to help you because what I think you want to do is not possible: the signature of the GetQueryResult method is illegal because T is unspecified (unless the method is a member of a generic type itself).
The method will not compile as given.
If you already know the type, you can change it to
public static List<T> GetQueryResult<T>(string xpathQuery)
{
var lst = new List<T>();
return lst;
}
but that's probably not what you want...
Generic type arguments are resolved compile time, so to have the code working you'd need to pass itemType as a type argument or change the return type to IList And Them use the solution given by ELisha but that would mean loosing type information on the Call site
Answer to the updated question:
public List<T> GetQueryResult<T>(string xPathQuery)
{
var items = ;// logic to get items
var list = new List<T>();
foreach (Sitecore.Data.Items.Item item in items)
{
list.Add((T) Activator.CreateInstance(typeof(T), item));
}
return list;
}
I assume that T has a constructor that gets Sitecore.Data.Items.Item, if it won't have the code will fail at runtime.
There must be a safer way to do it, it'll be better if you can give wider context to the problem.
As others have demonstrated, the only way to solve your updated question for any T is with reflection. However, if T is restricted to a well known set of types that you can modify, you could do this:
public interface IItemContainer
{
void SetItem(Sitecore.Data.Items.Item item);
}
public static List<T> GetQueryResult<T>(string xpathQuery)
where T : IItemContainer, new() {
IList<Sitecore.Data.Items.Item> items = GetAListOfItemsSomehow(xpathQuery);
List<T> result = new List<T>();
foreach (Sitecore.Data.Items.Item item in items) {
T obj = new T();
obj.SetItem(item);
result.add(obj);
}
return result;
}
Any types you want to use for T would then have to implement IItemContainer.
public static List<T> GetQueryResult<T>(string xpathQuery) {
List<T> lst = new List<T>();
return lst;
}
is the only way if you want static typing. Otherwise you could do
public static IList GetQueryResults(string xpathQuery, Type itemType) {
Type tp = typeof(List<>).MakeGenericType(itemType);
IList lst = (IList)Activator.CreateInstance(tp);
return lst;
}
but using a non-generic list would probably be better in that case.
Edit: You asked another question in the same post:
The 3 ways of creating an instance of a generic type are
use the where T : new() constraint and use the default constructor (doesn't seem good enough for you).
Use reflection. Rarely the best idea.
Specify a creator function
like this:
public static List<T> GetQueryResults<T>(string xpathQuery, Func<int, T> creator) {
var result = new List<T>();
foreach (i in something)
result.add(creator(i));
return result;
}
and then invoke it like:
List<int> l = GetQueryResults("something", i => new MyObject(i));
I have the following extension method to add the elements in one collection to another collection:
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> list)
{
foreach (var item in list)
{
collection.Add(item);
}
}
This works fine if the IEnumerable list is the same type as the ICollection I'm trying to add it to. However, if I have something like this:
var animals = new List<Animal>();
var dogs = new List<Dog>(); // dog is a subclass of animal
animals.AddRange(dogs); // this line has a compiler error, it can't infer the type
How do I modify my extension method to be able to do something like this, if the type of the IEnumerable is a subclass (or implements the interface) of the T type?
This method will give you what you want:
public static void AddRange<A,B>(
this ICollection<A> collection,
IEnumerable<B> list)
where B: A
{
foreach (var item in list)
{
collection.Add(item);
}
}
A couple of notes:
The only way that this can work is if you use a type for B that is derived from A. For example, Dog is a subclass of Animal, so AddRange will work. This is enforced by the "where B: A" clause. Without this, the ICollection.Add() call will fail due to an incompatible type for B being passed into the ICollection expecting an A.
There's not a lot of need to restrict the type of A to anything in the Animal type hierarchy; the extension method could be used anywhere you have one type deriving from another.
This isn't really a problem of the compiler not being able to infer the types. Even if you explicitly passed the types for A and B everywhere, you'll still get a compiler error.
You can do this:
public static void AddRange<T,T2>(this ICollection<T> collection, IEnumerable<T2> list) where T2: T {
foreach (var item in list) {
collection.Add(item);
} }
wait for C# 4.0 or use the Linq extension method Cast:
List<Animal> animals = new List<Animal>();
List<Dog> dogs = new List<Dog>();
animals.AddRange(dogs.Cast<Animal>());
I would use constraint to restrict the type.
public static void AddRange<T, TK>(this ICollection<T> collection, IEnumerable<TK> list) where TK : T
{
foreach (var item in list)
{
collection.Add(item);
}
}
public static void AddRange<TA, TB>(this ICollection<TA> collection,
IEnumerable<TB> list) where TB : TA
(incorporated Craig Walker's comment)
This is a compiler error (slightly changed for readability).
This one always puzzled me. FxCop tells that this is a bad thing to return List<T> and classes that are derived from Collection<T> should be preferable as return types.
Also, FxCop says that it is OK to use List<T> for internal data storage/manipulation. Ok, I get it, but what I don't get is why the compiler complains about trying to implicitly convert List<T> to Collection<T>. Isn't List<T> more interface-charged and functional? Why prohibit implicit conversion?
And another question that stems from above: is the new List<int>(some collection<int>) constructor expensive?
Why not just do the following:
Collection<string> collection = new Collection<string>(theList);
as Collection(IList input) takes a List as part of construction.
List<T> doesn't derive from Collection<T> - it does, however, implement ICollection<T>. That would be a better choice of return type.
As for the new List<int>(some collection<int>) question - it partly depends on what the collection is. If it implements ICollection<T> (at execution time) then the constructor can use its Count property to create the list with the right initial capacity before iterating through it and adding each item. If it doesn't implement ICollection<T> then it's just equivalent to:
List<int> list = new List<int>();
foreach (int x in otherCollection)
{
list.Add(x);
}
Still nice to have in a convenient constructor, but not hugely efficient - it can't be, really.
I don't believe the constructor does anything cunning for arrays, which it potentially could - using Array.Copy or whatever to just copy the lot in one go rather than iterating though. (Likewise if it were another List<T> it could get at the backing array and copy that directly.)
List<T> doesn't inherit from Collection<T>. Plain and simple. Unless List<T> provides an operator to implicitly convert to/from Collection<T>, you can't do it. I would actually suggest returning List<T> if you can, as I believe the rules go something like this:
Accept as a parameter the least constrictive interface possible.
Return as a return parameter the most constrictive type possible.
Here is a generic extension method written in C# 3.0 used to convert List<T> to Collection<T>
using System.Collections.Generic;
using System.Collections.ObjectModel;
public static class ExtensionMethods
{
public static Collection<T> ToCollection<T>(this List<T> items)
{
Collection<T> collection = new Collection<T>();
for (int i = 0; i < items.Count; i++)
{
collection.Add(items[i]);
}
return collection;
}
}
and it is used like this…
List<string> entities = new List<string>();
entities.Add("Value 1");
entities.Add("Value 2");
entities.Add("Value 3");
entities.Add("Value 4");
Collection<string> convertedEntities = entities.ToCollection<string>();
This is how you convert from List<T> to Collection<T> (while using LINQ):
The old function:
public List<Employee> GetEmployee(int id)
{
return ( from e in MyDataContext.Employees
select new Employee()
{
e.empId = id
}
).ToList();
}
After conversion:
using System.Collection.ObjectModel;
public Collection<Employee> GetEmployee(int id)
{
return new Collection<Employee>(
(from e in MyDataContext.Employees
select new Employee()
{
e.empId = id
}
).ToList() as IList<Employee>
);
}
You can use the the below
public class EmployeeCollection : Collection<Employee>
{
public EmployeeCollection(IList<Employee> list) : base(list)
{}
public EmployeeCollection() : base()
{}
}
Use the class like this
EmployeeCollection employeeCollection = new EmployeeCollection(list)
The other way around, it is not necessary to loop... you can make just .ToList()
ICollection<T> collection = new Collection<T>();
fill your collection using any method, and when you need the list, just do this:
List<T> list = collection.ToList();
after that you can use whatever you want with your list.
Have a good coding!
Does dot net have an interface like IEnumerable with a count property? I know about interfaces such as IList and ICollection which do offer a Count property but it seems like these interfaces were designed for mutable data structures first and use as a read only interface seems like an afterthought - the presence of an IsReadOnly field and mutators throwing exceptions when this property is true is IMO ample evidence for this.
For the time being I am using a custom interface called IReadOnlyCollection (see my own answer to this post) but I would be glad to know of other alternative approaches.
The key difference between the ICollection family and the IEnumerable family is the absence of certainty as to the count of items present (quite often the items will be generated/loaded/hydrated as needed) - in some cases, an Enumerable may not ever finish generating results, which is why the Count is missing.
Deriving and adding a Count is possible depending on your requirements, but it goes against this spirit, which is the purpose of ICollection - a collection of stuff that's all there.
Another way might be to use the System.Linq.Enumerable.Count method, i.e.
using System.Linq;
class X
{
void Y(IEnumerable<int> collection)
{
int itemCount = collection.Count();
}
}
or use the (System.Linq.Enumerable) .ToList() to pull all the items from the enumerator into a Collection and work from there.
(Also to answer your comment before having 50 rep:- the ".Count()" bit is a call to an extension method on the extension class System.Linq.Enumerable - the extension method is available on all things that derive from IEnumerable because the code has a "using System.Linq" which brings the extension methods in all classes in that namespace into scope - in this case its in the class Enumerable. If you're in VS, pressing F12 will bring you to the definition of S.L.Enumerable. BTW C# In Depth is a fantastic book for learning LINQ properly - its a page turner thats really helps you get the whole picture compared to learning the bits of LINQ piece by piece)
As of .Net 4.5, there are two new interfaces for this: IReadOnlyCollection<T> and IReadOnlyList<T>.
IReadOnlyCollection<T> is IEnumerable<T> with a Count property added, IReadOnlyList<T> also adds indexing.
It sounds like you really just want ReadOnlyCollection<T> - expose it as IList<T>, but by wrapping the original list like this you just get a read-only wrapper with an appropriate count.
Taking into consideration some of the comments I have decided to go with a wrapper class implementing a custom interface...
interface IReadOnlyCollection<T> : IEnumerable<T>
{
int Count { get; }
}
//This can now be not misused by downcasting to List
//The wrapper can also be used with lists since IList inherits from ICollection
public class CollectionWrapper<T> : IReadOnlyCollection<T>
{
public CollectionWrapper(ICollection<T> collection)
{
_collection = collection;
}
public int Count
{
get
{
return _collection.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
return (IEnumerator<T>)_collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)((IEnumerable)_collection).GetEnumerator();
}
////////Private data///////
ICollection<T> _collection;
}
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
CollectionWrapper<int> collection = new CollectionWrapper<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection)
{
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection)
{
Console.WriteLine(x);
}
}
}
Thanks all for your suggestions.
Edit: Now cannot be misused by downcasting to List (or whatever).
IList can return IsReadOnly as true, which marks the collection as readonly. Other than that I'm afraid I don't know of anything fitting.
Since it's an interface, you would have to implement the Count property yourself, why don't you create a new interface that inherits IEnumerator and add a Count property?
IList or ICollection would be the way to go, if you want to use the standard interfaces.
Note that you can "hide" methods required by the interface if you don't want them in your class's public interface -- for example, since it's meaningless to add things to a readonly collection you can do this:
void ICollection<DataType>.Add(DataType item)
{
throw new NotSupportedException();
}
public DataType this[int index]
{
get { return InnerList[index]; }
}
DataType IList<DataType>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException(); }
}
etc.
An array can be cast to an IList, which makes the IList ReadOnly == true :)
You can get .Count on IEnumerable with an extension method if you add a reference to System.Linq (in 3.5 anyway).
As Jon Skeet mentions, you're much better off using System.Collections.ObjectModel.ReadOnlyCollection instead of creating your own wrapper class.
Then you can implement your sample as follows:
class Program {
static void Main(string[] args) {
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
ReadOnlyCollection<int> collection = new ReadOnlyCollection<int>(list);
Console.WriteLine("Count:{0}", collection.Count);
foreach (var x in collection) {
Console.WriteLine(x);
}
foreach (var x in (IEnumerable)collection) {
Console.WriteLine(x);
}
}
}