Generic method with variance in C#? - c#

Consider following classes (inheritance tree):
public class A {}
public class B: A {}
And this method:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
The compiler is unhappy. Error is Cannot convert expression type IList<B> to return type IList<A>. How do I solve this ? In another words how to specify that MyMethod will return IList<T> of T where T can be anything that inherits from A or instances of A itself ?

What you're asking for is impossible because IList<T> does not support variance -- you cannot use IList<B> anywhere that is expecting IList<A>. You'll have to explain more details of what you want in order to come up with a solution.
Possible solutions are:
public IList<A> MyMethod(){
IList<A> result = new List<A>();
//add some items to result
return result;
}
Or
public IEnumerable<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}

You cannot convert an IList<B> to IList<A>, even if B inherits from A. Otherwise, the user might attempt to add an instance of A that is not B into the list.
public void Example(){
IList<B> listB = new List<B>();
IList<A> listA = listB;
listA.Add(new A()); // Can't insert A into a list of B
}
Can you return IEnumerable<A> instead of IList<A>? IEnumerable<A> is covariant, unlike IList<A>.

how to specify that MyMethod will return IList of T where T can be anything that inherits from A or instances of A itself ?
You don't have to
You can just declare that it returns IList<A>. Why? Becase - given that B inherits from A - every item of B can be passed where the requiered type is A.
Call it polymorphism by inheritance, Liskov substitution principle, or method variance, the name doesn't matter. What matters is that the following works (tested on LinqPad):
public class A {}
public class B: A {}
public IList<A> MyMethod()
{
var result = new List<A>();
//add some items to result
result.Add(new B());
return result;
}
Genetic alternatives
In fact, you can tell that you are going to return a IList<TA> and request a few derived types (TB, TC...) to populate it with. That's right, the following example also works (tested on LinqPad):
void Main()
{
MyMethod<A, B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<TA> MyMethod<TA, TB, TC>()
where TB : TA, new()
where TC : TA, new()
where TA : class
{
var result = new List<TA>();
//add some items to result
result.Add(new B() as TA);
result.Add(new C() as TA);
return result;
}
Or if you want to keep a particular base type (say you want to return an IList<A> but it actually contains items of classes that derive from A, then you can do this:
void Main()
{
MyMethod<B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<A> MyMethod<T1, T2>()
where T1 : A, new()
where T2 : A, new()
{
var result = new List<A>();
//add some items to result
result.Add(new T1() as A);
result.Add(new T2() as A);
return result;
}
You don't have to, but you can
OK, if you really want to say it returns IList<T> where T : A. Then say that!
void Main()
{
MyMethod<B>();
}
public class A {}
public class B: A {}
//public class C: A {} //Even if I don't add that class
public IList<T> MyMethod<T>()
where T : A, new()
{
var result = new List<T>();
//add some items to result
result.Add(new T());
return result;
}
Yes, that one cannot return a mix of item of type T and items of type A, because it says it returns IList<T> and not every item of type A is also an item of type T.
What happens with your code
Look at your code:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
You are trying to return an IList<B> when you said that you was going to return an IList<A>. Let's suppose that that works... then what would happen to the caller of your method? Let's see:
public class A {}
public class B: A {}
public class C: A {}
void Main()
{
//Hmmm... I need a IList<T>, let's call MyMethod!
IList<A> list = MyMethod();
//Cool, I got an IList<A>, now let's add some items...
var item = new C();
//Well, item is of type C...
// and C inherits from A, so I must be able to add it...
list.Add(item); //BOOM!
//It was actually an IList<B>!
// and C doesn't dervive from B, so you can't add it.
}
DFTBA!

Related

Casting an Enumerable.Empty<>() into another class that implements IEnumerable returns null

I have a class that implements IEnumerable:
public class A { }
public class B : IEnumerable<A> { }
How can i use class B as Enumerable.Empty<A>() in this case?
I mean that casting like this Enumerable.Empty<A>() as B returns null. Why it does? Should i implement any specific constructor or a method? Or is it an forbidden operation and I should to do it in the other way?
Enumerable.Empty<T>() is implemented as:
internal class EmptyEnumerable<T>
{
public static readonly T[] Instance = new T[0];
}
public static IEnumerable<T> Empty<T>()
{
return EmptyEnumerable<T>.Instance;
}
If you remove the optimization to cache the empty array, you could rewrite this as:
public static IEnumerable<T> Empty<T>()
{
return new T[0];
}
So Enumerable.Empty<T>() just returns an empty array of type T.
You wouldn't write:
B b = new A[0];
This doesn't make sense: a B isn't an array of instances of A.
For the same reason, you can't write:
B b = Enumerable.Empty<A>();

c# conversion generic inherited as base returns null [duplicate]

While we can inherit from base class/interface, why can't we declare a List<>
using same class/interface?
interface A
{ }
class B : A
{ }
class C : B
{ }
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
List<A> listOfA = new List<C>(); // compiler Error
}
}
Is there a way around?
The way to make this work is to iterate over the list and cast the elements. This can be done using ConvertAll:
List<A> listOfA = new List<C>().ConvertAll(x => (A)x);
You could also use Linq:
List<A> listOfA = new List<C>().Cast<A>().ToList();
First of all, stop using impossible-to-understand class names like A, B, C. Use Animal, Mammal, Giraffe, or Food, Fruit, Orange or something where the relationships are clear.
Your question then is "why can I not assign a list of giraffes to a variable of type list of animal, since I can assign a giraffe to a variable of type animal?"
The answer is: suppose you could. What could then go wrong?
Well, you can add a Tiger to a list of animals. Suppose we allow you to put a list of giraffes in a variable that holds a list of animals. Then you try to add a tiger to that list. What happens? Do you want the list of giraffes to contain a tiger? Do you want a crash? or do you want the compiler to protect you from the crash by making the assignment illegal in the first place?
We choose the latter.
This kind of conversion is called a "covariant" conversion. In C# 4 we will allow you to make covariant conversions on interfaces and delegates when the conversion is known to be always safe. See my blog articles on covariance and contravariance for details. (There will be a fresh one on this topic on both Monday and Thursday of this week.)
To quote the great explanation of Eric
What happens? Do you want the list of giraffes to contain a tiger? Do you want a crash? or do you want the compiler to protect you from the crash by making the assignment illegal in the first place?
We choose the latter.
But what if you want to choose for a runtime crash instead of a compile error? You would normally use Cast<> or ConvertAll<> but then you will have 2 problems: It will create a copy of the list. If you add or remove something in the new list, this won't be reflected in the original list. And secondly, there is a big performance and memory penalty since it creates a new list with the existing objects.
I had the same problem and therefore I created a wrapper class that can cast a generic list without creating an entirely new list.
In the original question you could then use:
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
IList<A> listOfA = new List<C>().CastList<C,A>(); // now ok!
}
}
and here the wrapper class (+ an extention method CastList for easy use)
public class CastedList<TTo, TFrom> : IList<TTo>
{
public IList<TFrom> BaseList;
public CastedList(IList<TFrom> baseList)
{
BaseList = baseList;
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }
// IEnumerable<>
public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }
// ICollection
public int Count { get { return BaseList.Count; } }
public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
public void Clear() { BaseList.Clear(); }
public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }
// IList
public TTo this[int index]
{
get { return (TTo)(object)BaseList[index]; }
set { BaseList[index] = (TFrom)(object)value; }
}
public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}
public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
public IEnumerator<TFrom> BaseEnumerator;
public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
{
BaseEnumerator = baseEnumerator;
}
// IDisposable
public void Dispose() { BaseEnumerator.Dispose(); }
// IEnumerator
object IEnumerator.Current { get { return BaseEnumerator.Current; } }
public bool MoveNext() { return BaseEnumerator.MoveNext(); }
public void Reset() { BaseEnumerator.Reset(); }
// IEnumerator<>
public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}
public static class ListExtensions
{
public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
{
return new CastedList<TTo, TFrom>(list);
}
}
If you use IEnumerable instead, it will work (at least in C# 4.0, I have not tried previous versions). This is just a cast, of course, it will still be a list.
Instead of -
List<A> listOfA = new List<C>(); // compiler Error
In the original code of the question, use -
IEnumerable<A> listOfA = new List<C>(); // compiler error - no more! :)
As far as why it doesn't work, it might be helpful to understand covariance and contravariance.
Just to show why this shouldn't work, here is a change to the code you provided:
void DoesThisWork()
{
List<C> DerivedList = new List<C>();
List<A> BaseList = DerivedList;
BaseList.Add(new B());
C FirstItem = DerivedList.First();
}
Should this work? The First item in the list is of Type "B", but the type of the DerivedList item is C.
Now, assume that we really just want to make a generic function that operates on a list of some type which implements A, but we don't care what type that is:
void ThisWorks<T>(List<T> GenericList) where T:A
{
}
void Test()
{
ThisWorks(new List<B>());
ThisWorks(new List<C>());
}
You can only cast to readonly lists. For example:
IEnumerable<A> enumOfA = new List<C>();//This works
IReadOnlyCollection<A> ro_colOfA = new List<C>();//This works
IReadOnlyList<A> ro_listOfA = new List<C>();//This works
And you cannot do it for lists that support saving elements. The reason why is:
List<string> listString=new List<string>();
List<object> listObject=(List<object>)listString;//Assume that this is possible
listObject.Add(new object());
What now? Remember that listObject and listString are the same list actually, so listString now have object element - it shouldn't be possible and it's not.
For your problem there are several native C# possibilities:
dynamic
Array
IReadOnlyList, IEnumerable
Use List<> the proper way.
All of them work well! There is no need for any tricky programming!
Here are examples for each of them:
1. dynamic: The most universal solution
type checking at runtime
you abandon your compiler error checking support, so handle with care! If you try to add an element of wrong type, you'll only get a runtime error!
you even can assign collections of unrelated classes.
Simply write dynamic listOfA = new List<C>(); instead of List<A> listOfA = new List<C>();
At first the interface and class definitions for all of the examples:
using System;
using System.Collections.Generic;
using System.Linq;
interface IAnimal
{
public string Name { get; }
}
class Bear : IAnimal
{
public string BearName = "aBear";
public string Name => BearName;
}
class Cat : IAnimal
{
public string CatName = "aCat";
public string Name => CatName;
}
// Dog has no base class/interface; it isn't related to the other classes
class Dog
{
public string DogName = "aDog";
public string Name => DogName;
}
Here is the example using dynamic
public class AssignDerivedClass
{
public static void TestDynamicListAndArray()
{
dynamic any = new List<Bear>() // List of derived
{
new Bear() { BearName = "Bear-1" },
new Bear() { BearName = "Bear-2" }
};
//any[0].CatName = "NewCat"; // => Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
Console.WriteLine($"Bear names: {any[0].BearName}, {Name(any[1])}");
any = new Cat[] // Array of derived
{
new Cat() { CatName = "Cat-3" },
new Cat() { CatName = "Cat-4" }
};
Console.WriteLine($"Cat names: {any[0].CatName}, {any[1].Name}");
any = new List<Dog>() // List of non-related class
{
new Dog() { DogName = "Dog-5" },
new Dog() { DogName = "Dog-6" }
};
Console.WriteLine($"Dog names: {any[0].DogName}, {Name(any[1])}");
any = new List<IAnimal>() // List of interface
// any = new IAnimal[] // Array of interface works the same
{
new Bear() { BearName = "Bear-7" },
new Cat() { CatName = "Cat-8" }
};
Console.WriteLine($"Animal names: {any[0].BearName}, {any[1].CatName}");
any[0].BearName = "NewBear";
Console.WriteLine($"Animal names: {Name(any[0])}, {any[1].Name}");
}
private static string Name(dynamic anymal)
{
return anymal switch
{
Bear bear => bear.BearName,
Cat cat => cat.CatName,
Dog dog => dog.DogName,
_ => "No known Animal"
};
}
// Bear names: Bear-1, Bear-2
// Cat names: Cat-3, Cat-4
// Dog names: Dog-5, Dog-6
// Animal names: Bear-7, Cat-8
// Animal names: NewBear, Cat-8
}
2. Array: Creating a Bear[] array, it is guaranteed that all array elements reference instances of Bear.
You can exchange elements, but you can't remove or add new elements.
Trying to set a wrong type yields a runtime error.
public static void TestArray()
{
Bear[] bears = { new Bear(), null };
IAnimal[] bearAnimals = bears;
//bearAnimals[1] = new Cat(); // System.ArrayTypeMismatchException
bearAnimals[1] = new Bear() { BearName = "Bear-1" };
Console.WriteLine($"Bear names: {bearAnimals[0].Name}, {bears[1].BearName}");
}
// Result => Bear names: aBear, Bear-1
3. IReadOnlyList, IEnumerable:
Assign your List<C> to an IEnumerable<A> or IReadOnlyList<A>
Neither of them can be changed at runtime, i.e. you can't Add or Remove elements.
Why should the compiler allow assigning your List<C> to a List<A> instead of IReadOnlyList<A> when adding an element will lead to an error anyway?
public static void TestIEnumerableAndIReadonlyList()
{
var cats = new List<Cat>()
{
new Cat() { CatName = "Cat-3" },
new Cat() { CatName = "Cat-4" }
};
IEnumerable<IAnimal> iEnumerable = cats;
Console.WriteLine($"Cat names: {(iEnumerable.ElementAt(0) as Cat).CatName}, "
+ Name(iEnumerable.Last()));
IReadOnlyList<IAnimal> iROList = cats;
Console.WriteLine($"Cat names: {iROList[0].Name}, {Name(iROList[1])}");
//iROList.Add(new Cat()); // compiler error CS61: no definition for 'Add'
}
// Result:
// Cat names: Cat-3, Cat-4
// Cat names: Cat-3, Cat-4
4. Use List<> the proper way: List<A> listOfA = new List<A>()
Define a List of your interface
Assign instances of one derived class only - you didn't want to store other classes anyway, did you?
public static void TestListOfInterface()
{
var bears = new List<IAnimal>()
{
new Bear() { BearName = "Bear-1" },
new Cat() { CatName = "Cat-3" },
};
bears.Add(new Bear() { BearName = "Bear-2" });
string bearNames = string.Join(", ", bears.Select(animal => animal.Name));
Console.WriteLine($"Bear names: {bearNames}");
string bearInfo0 = VerifyBear(bears[0]);
string bearInfo1 = VerifyBear(bears[1]);
Console.WriteLine($"One animal is {bearInfo0}, the other one is {bearInfo1}");
string VerifyBear(IAnimal bear)
=> (bear as Bear)?.BearName ?? "disguised as a bear!!!";
}
// Bear names: Bear-1, Cat-3, Bear-2
// One animal is Bear-1, the other one is disguised as a bear!!!
I personally like to create libs with extensions to the classes
public static List<TTo> Cast<TFrom, TTo>(List<TFrom> fromlist)
where TFrom : class
where TTo : class
{
return fromlist.ConvertAll(x => x as TTo);
}
Because C# doesn't allow that type of inheritance conversion at the moment.
This is an extension to BigJim's brilliant answer.
In my case I had a NodeBase class with a Children dictionary, and I needed a way to generically do O(1) lookups from the children. I was attempting to return a private dictionary field in the getter of Children, so obviously I wanted to avoid expensive copying/iterating. Therefore I used Bigjim's code to cast the Dictionary<whatever specific type> to a generic Dictionary<NodeBase>:
// Abstract parent class
public abstract class NodeBase
{
public abstract IDictionary<string, NodeBase> Children { get; }
...
}
// Implementing child class
public class RealNode : NodeBase
{
private Dictionary<string, RealNode> containedNodes;
public override IDictionary<string, NodeBase> Children
{
// Using a modification of Bigjim's code to cast the Dictionary:
return new IDictionary<string, NodeBase>().CastDictionary<string, RealNode, NodeBase>();
}
...
}
This worked well. However, I eventually ran into unrelated limitations and ended up creating an abstract FindChild() method in the base class that would do the lookups instead. As it turned out this eliminated the need for the casted dictionary in the first place. (I was able to replace it with a simple IEnumerable for my purposes.)
So the question you might ask (especially if performance is an issue prohibiting you from using .Cast<> or .ConvertAll<>) is:
"Do I really need to cast the entire collection, or can I use an abstract method to hold the special knowledge needed to perform the task and thereby avoid directly accessing the collection?"
Sometimes the simplest solution is the best.
You can also use the System.Runtime.CompilerServices.Unsafe NuGet package to create a reference to the same List:
using System.Runtime.CompilerServices;
...
class Tool { }
class Hammer : Tool { }
...
var hammers = new List<Hammer>();
...
var tools = Unsafe.As<List<Tool>>(hammers);
Given the sample above, you can access the existing Hammer instances in the list using the tools variable. Adding Tool instances to the list throws an ArrayTypeMismatchException exception because tools references the same variable as hammers.
I've read this whole thread, and I just want to point out what seems like an inconsistency to me.
The compiler prevents you from doing the assignment with Lists:
List<Tiger> myTigersList = new List<Tiger>() { new Tiger(), new Tiger(), new Tiger() };
List<Animal> myAnimalsList = myTigersList; // Compiler error
But the compiler is perfectly fine with arrays:
Tiger[] myTigersArray = new Tiger[3] { new Tiger(), new Tiger(), new Tiger() };
Animal[] myAnimalsArray = myTigersArray; // No problem
The argument about whether the assignment is known to be safe falls apart here. The assignment I did with the array is not safe. To prove that, if I follow that up with this:
myAnimalsArray[1] = new Giraffe();
I get a runtime exception "ArrayTypeMismatchException". How does one explain this? If the compiler really wants to prevent me from doing something stupid, it should have prevented me from doing the array assignment.
May be late.
Conversion to Array can also do the job.
main()
{
List<Camel> camels = new List<Camel>();
Reproducton(camels.ToArray());
}
public void Reproducton(Animal[] animals)
{
foreach(var animal in animals.ToList())
{
var baby = animal.Reproduce();
}
}

Cast class A to class B without generics

I have two classes that have no connection to one another :
public class A
{
public String Address {get;set}
}
public class B
{
public String Address {get;set}
}
List<A> addressList = DB.Addresses.GetAll();
When I do
List<B> addressListOther = addressList.Cast<B>().ToList();
the output is :
Additional information: Unable to cast object of type 'A' to type 'B'.
Any idea how to fix that ?
You can use Select() instead of that way:
List<B> addressListOther = addressList.Select(a => new B { Address = a.Address}).ToList();
Or you can override explicit operator in class B:
public static explicit operator B(A a) // explicit A to B conversion operator
{
return new B { Address = a.Address };
}
And, then:
List<B> addressListOther = aList.Select(a => (B)a).ToList();
The reason of this exception:
Cast will throw InvalidCastException, because it tries to convert A to object, then cast it to B:
A myA = ...;
object myObject = myA ;
B myB= (B)myObject; // Exception will be thrown here
The reason of this exception is, a boxed value can only be unboxed to a variable of the exact same type.
Additional Information:
Here is the implemetation of the Cast<TResult>(this IEnumerable source) method, if you interested:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
if (typedSource != null) return typedSource;
if (source == null) throw Error.ArgumentNull("source");
return CastIterator<TResult>(source);
}
As you see, it returns CastIterator:
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
foreach (object obj in source) yield return (TResult)obj;
}
Look at the above code. It will iterate over source with foreach loop, and converts all items to object, then to (TResult).
They do not inherit from each other so you can't do that. The Cast<T> iterates over the collection and tries to cast the items to the specified type.
If you do the following you will fail to0:
A a = new A { Address = "a"};
B b = (B)a; // Compile error of: Cannot convert type A to B
Instead use Select to project new B items.
List<B> addressListOther = addressList.Select(a => new B { Address = a.Address}).ToList();
Another way is to override the implicit operator in class A:
public static implicit operator B(A a)
{
return new B { Address = a.Address };
}
And then the followingcode will word:
List<A> aList = new List<A> { new A { Address = "a" } };
List<B> bList = aList.Select(a => (B)a).ToList();
The simpliest way for me is to introduce a superclass.
public class ClassWithAddress
{
public string Address{get;set;}
}
Then you'll derive every class from that class and delete the address property like this:
public class A : ClassWithAddress
{
}
public class B : ClassWithAddress
{
}
After that you can do your list operations concerning the Address Property with the superclass ClassWithAddress.

C# generic method can't create List<T>

I have one Interface and two classes.
public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }
I have a generic method,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
...
}
which should return a object-list based on data in DataTable. So, I create a list in this method which I want to return at the end. I thought I could do the following,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
List<T> myList = new List<T>;
// Now I thought I could easily add Objects based on T because,
// both classes implement the interface
if (typeof(T) == typeof(B))
{
myList.Add(new B());
}
else
{
myList.Add(new A());
}
return myList;
}
But the compiler tells me that "Argument type A (B) is not assigneable"! Why is it not assignable?
Ok, alternatively can I do the following,
private List<T> GetList<T>(DataTable table)
where T : class, IMyInterface
{
List<IMyInterface> myList = new List<IMyInterface>;
// Now I can assign the Object's :)
if (typeof(T) == typeof(B))
{
myList.Add(new B());
}
else
{
myList.Add(new A());
}
return myList as List<T>;
}
The compiler didn't complain but the result of the return clause is always null. For sure there are values in myList. The cast seems to fail. Someone please help me to solve this problem more elegantly.
One way is to add new() constraint. Limitation is that you need a public parameterless constructor for the type argument T.
private static List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
List<T> myList = new List<T>();
T instance = new T();
//access anything defined in `IMyInterface` here
myList.Add(instance);
return myList;
}
I don't understand what you're trying to do here. Why do you even need generics?
You were going the right way initially, deriving your types from the same interface, so make use of it. Declare your list List<IMyInterface> and simply add your objects as they are.
If later you actually need a physical representation of an enumerable with concrete A or B types, you have OfType<>() and Cast<>() for it, though it shows your polymorphism was done wrong in the first place.
Add a new constraint
private List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
return new List<T>(){ new T() };
}
You should cast object, before add it to List:
private static List<T> GetList<T>(DataTable table) where T : class, MyInterface
{
List<T> myList = new List<T>();
//Now i thought i can easily add Objects based on T, because both classes
//implement the interface
if (typeof (T) == typeof (B))
{
// use of 'as' operator
myList.Add(new B() as T);
}
else
{
myList.Add(new A() as T);
}
return myList;
}
But anyway I am not getting a point, what your are trying to achieve.
Also myList as List<T> will surely result as null, since you cannot cast generic collection with as operator as List<T> is not declared as Covariant. You should explicitly call .Cast<T>() method to create new collection.
I'm guessing you actually want to do something like,
public IList<T> GetList<T>(
DataTable table,
Func<DataRow, T> extractor)
{
var result = new T[table.Rows.Count];
for (var i = 0; i < table.Rows.Count; i++)
{
result[i] = extractor(table.Rows[i]);
}
return result;
}
extractor being the delegate for converting a DataRow to T.
this would work more simply than you might expect,
// referencing System.Data.DataSetExtensions
var list = GetList(
data,
row => new A
{
Id = row.Field<int>("id"),
...
});
list would be an IList<A> among other types.
Try this:
private List<T> GetList<T>(DataTable table) where T : class, IMyInterface {
List<T> myList = new List<T>();
if (typeof(T) == typeof(B)) {
myList.Add((T)new B());
}
else {
myList.Add((T)new A());
}
return myList
}
Right only for class A and B
static List<T> GetList<T>(DataTable table) where T : class, IMyInterface
{
List<T> myList = new List<T>();
IMyInterface obj;
if (typeof(T) == typeof(B))
{
obj = new B();
}
else
{
obj = new A();
}
myList.Add((T)obj);
return myList;
}

One liner for concatenation of two different lists of objects with the same interface

Consider this simple code:
public interface Iinterface { }
public class Foo : Iinterface { }
public class Bar : Iinterface { }
[TestMethod()]
public void Test_Concat()
{
var bars = new List<Bar>();
var foos = new List<Foo>();
// Ok
IEnumerable<Iinterface> concats1 = bars.Cast<Iinterface>().Concat(foos.Cast<Iinterface>());
// Compilation error
IEnumerable<Iinterface> concats2 = bars.Concat(foos);
}
I want to concat two lists in one in one line, and keeping a type safety at compile time.
If for example, I delete the interface for the class Foo, this will still compile, but fail at runtime:
public interface Iinterface { }
public class Foo { }
public class Bar : Iinterface { }
[TestMethod()]
public void Test_Concat()
{
var bars = new List<Bar>();
var foos = new List<Foo>();
IEnumerable<Iinterface> concats1 = bars.Cast<Iinterface>().Concat(foos.Cast<Iinterface>());
}
If I use OfType<T>(), this will not fail at runtime, but I want it to fail at compile time.
The best I could find is to use this 3 line of codes:
var list = new List<Iinterface>();
list.AddRange(bars);
list.AddRange(foos);
But for something that simple, I want to find a one-liner, and if possible retrieve an IEnumerable<Iinterface> instead of a List<Iinterface>.
Is there any way to achieve this?
You could just write your own method?
Since IEnumerable is covariant you only need to specify the base
var list= Combine<IInterface>(foos, bars);
private IEnumerable<T> Combine<T>(IEnumerable<T> ListA, IEnumerable<T> ListB)
{
foreach (T t in ListA)
yield return t;
foreach (T t in ListB)
yield return t;
}
Although you might as well just write
var list= foos.Concat<IInterface>(bars);
How about making your custom Concat extension method version:
public static class MyEnumerable
{
public static IEnumerable<T> Concat<T, T1, T2>(this IEnumerable<T1> source, this IEnumerable<T2> other)
where T1 : T
where T2 : T
{
return source.Cast<T>().Concat(other.Cast<T>());
}
}
Usage:
var items = foos.Concat<Iinterface, Foo, Bar>(bars);
It has compile-time safety, and will not compile if any of Foo and Bar does not implement Iinterface.
It should also support differed execution out of the box, because used LINQ methods do.
In fact, the concat method already did what I want, I juste need to help a little by specifying the return type, because there is no type inference on return types.
public interface Iinterface { }
public class Foo : Iinterface { }
public class Bar : Iinterface { }
[TestMethod()]
public void Test_Concat()
{
var bars = new List<Bar>();
var foos = new List<Foo>();
var list = foos.Concat<Iinterface>(bars);
}
I'm so used to use inference that I forgot that sometimes, compiler need hints!
You can do this instead:
public void Test_Concat2()
{
IEnumerable<Iinterface> bars = new List<Bar>();
IEnumerable<Iinterface> foos = new List<Foo>();
IEnumerable<Iinterface> concats = bars.Concat(foos);
}
If you then change the definition Foo or Bar so it no longer has the interface, you will get a compile-time error.
The problem appears to be in the Cast not the Concat. The declarations are as follows:
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);
In Concat, both enunerables are strongly typed, but Cast does not constrain the source type so the problem occurs at runtime instead of compile time.
Trying a MyCast implementation as follows fails at run time at (TResult) s
public static IEnumerable<TResult> MyCast<TResult>(this IEnumerable source)
{
var result = (from object s in source select (TResult) s).ToList();
return result.AsEnumerable();
}
If implementing a bit of type checking in a new Cast like so:
public static IEnumerable<TResult> MyCast2<TSource, TResult>(this IEnumerable<TSource> source)
where TSource : TResult
{
var result = (from object s in source select (TResult)s).ToList();
return result.AsEnumerable();
}
then the calling line needs two type params like so
IEnumerable<Iinterface> concats3 = bars.Concat(foos.MyCast2<Foo, Iinterface>());
and the compiler detects that Foo is not convertible to Iinterface.
Of course, specifying the return type on Concat is more concise.

Categories