I'm trying to create an instance of a class that I can add to a list in a generic way..
I know the type of class that needs to be made and i've been able to make an object of the class using the code below but I have not found a way to create a cast that will allow me to add this to a list.. any ideas?
T is the same as objType
public static List<T> LoadList(string fileName, Type objType)
{
List<T> objList = new List<T>();
object o = Activator.CreateInstance(objType);
objList.Add((**o.GetType()**)o);
return objList;
}
if theres a better way of doing this too im open to ideas :)
Just use the non-generic API:
((IList)objList).Add(o);
I'm also assuming that type is a generic type-parameter; just to say: type is confusing for this; T or TSomethingSpecific would be more idiomatic.
Also: this line needs fixing:
List<type> objList = new List<type>(); // <=== not new List<Object>
Given that <type> is the same as objType, I'd suggest dropping the reflection and using the where T : new() type constraint:
public static List<T> LoadList(string fileName)
where T : new()
{
List<T> objList = new List<T>();
objList.add(new T());
return objList;
}
Edit:
If objType is a subclass of T, then I think something along these lines should work:
public static List<TListType, T> LoadList(string fileName)
where T : TListType, new()
{
List<TListType> objList = new List<TListType>();
objList.add(new T());
return objList;
}
You could user Zach Johnson's suggestion with the where constraint as it eliminates a duplicate specification of the type. However if the signature is set in stone, you could get by with a simple as cast, like:
public List<T> LoadList<T>(Type objType) where T : class
{
List<T> objList = new List<T>();
T item = (Activator.CreateInstance(objType) as T);
objList.Add(item);
return objList;
}
This also needs a where restriction, because in order to cast to a type, that type must be a reference type (aka class).
Related
In a generic method like : public T getList<T>(),
I have a List and I need to convert it in type T to return it.
public T getList<T>()
{
List<object> someObjects = getListObject(); // Get object from any where.
return (dynamic)someObjects; // Casting don't work
}
I call this method with T is of type List<myClass>, like this :
List<myClass> myClassList = getList<List<myClass>>()
Then I have a runtime exception who said that I can't convert List<object> to List<myClass>
It's normal, and I understand why.
But how can I do someting like that ?
I have tryed same thing with this method :
public List<T> getList<T>()
{
List<object> someObjects = getListObject(); // Get object from any where.
return (dynamic)someObjects.OfType<T>.ToList<T>; // that work good
}
Now I call this method with T is of type myClass, like this :
List<myClass> myClassObjects = getList<myClass>()
It work good, but I need to use this method with T is of type List<myClass>
I think your getList<T> method is defined slightly wrong. You want to return a generic list. I made your implementation static, but it doesn't need to be. The getList<T> method can be an instance method as well.
Hopefully, this is what you need:
public class TemplateExamples
{
public static List<T> getList<T>()
{
List<T> someObjects = new List<T>();
return someObjects;
}
}
here's an example of using it:
public class TestTemplateExamples
{
public static void Main()
{
var intList = TemplateExamples.getList<int>();
var stringList = TemplateExamples.getList<string>();
var templateList = TemplateExamples.getList<TemplateExamples>();
}
}
Thnx
For reasons, a given List<object> can be assigned or cast to a List<T> but you can cast each element in a List<object> to T and if there are no errors, return that.
However, you can't easily get at the generic type parameter of the type passed in, so you need to pass in the element type:
public List<T> getList<T>() {
List<object> someObjects = getListObject(); // Get object from any where.
return someObjects.Cast<T>().ToList();
}
This uses the LINQ Cast method to cast each element and creates a new List<T> from the result.
I'm trying to make a generic function that converts a enum System.Array into a List of those enums, I can not know the type of the enum array. I have tried several ways but I have not been able to make it work. It would be something like this..., Thanks
public static List<T> SArrayEnumToList<T>(System.Array arr){
Type enumType = typeof(T);
if(enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
List<T> enumList = new List<T>(new T[arr.Length]);
int i;
for(i=0;i<arr.Length;i++) {
enumList.Add(( T )Enum.Parse(enumType, arr.GetValue(i).ToString()));
}
return enumList;
}
You only really need to use the Linq ToList() method:
var myEnumsList = myEnumsArray.ToList();
The documentation states that ToList() returns a list "that contains elements from the input sequence".
If you really want to break this functionality out to your own method, you may do this like following:
private static List<T> ToList<T>(T[] enums) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum.");
}
return enums.ToList();
}
Constraining type of generic type T limits what types may be used when calling the method. Enum is a struct and implements IConvertible as discussed in here.
EDIT:
Since you really need to use System.Array. Iterate the System.Array, cast every value to generic type T and add to list before returning.
Working example:
public static List<T> ToList<T>(Array array) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum.");
}
List<T> enumValues = new List<T>();
foreach (var enumValue in array)
{
enumValues.Add((T)enumValue);
}
return enumValues;
}
EDIT #2
Update after comments.
public static IList ToList(Array array)
{
Type elementType = array.GetType().GetElementType();
Type listType = typeof(List<>).MakeGenericType(new[] { elementType });
IList list = (IList)Activator.CreateInstance(listType);
foreach (var enumValue in array)
{
list.Add(enumValue);
}
return list;
}
Assuming you have a array of int, this should work i guess
public static List<T> SArrayEnumToList<T>(int[] arr) where T : struct, IConvertible
{
if (!typeof (T).IsEnum)
throw new ArgumentException("T must be of type System.Enum");
// cast to object first
return arr.Cast<object>()
.Cast<T>()
.ToList();
}
// or
public enum Test
{
blah,
balh2,
blah3
}
...
var results = ((Test[])(object)values).ToList();
Full Demo Here
I'm not totally convinced this is possible, but here goes. I have a method returning an object, although the actual type is Collection. Now, I can easily cast the object into the collection using
var myCollection = myObject as Collection<MyClassA>;
However the problem I have is that Collection<MyClassA> could alternatively be Collection<MyClassB> or Collection<MyClassC>. All of these MyClassX's are inherited from MyBaseClass, so ideally I would like to be able to do something like
var myCollection = myObject as Collection<MyBaseClass>;
However this throws an exception when casting. Is it possible to do this in anyway? I understand that it may be within .Net 4?
Thanks for the help.
EDIT:
OK - The answers so far are very useful, however they only solve the second part of the solution - converting/casting collections.
I am still unsure as to how I should initially cast the object to a collection (without the use of a huge if statement for each of the possible types)
This is only supported with IEnumerable<T> in .NET 4. Check out the difference in the signatures:
IEnumerable<T>:
public interface IEnumerable<out T> : IEnumerable
Collection<T>:
public class Collection<T> : IList<T>,
ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
That out keyword in the type parameter is what tells .NET to support variance.
Before I had access to .NET 4 I wrote an extension method that achieved this:
public static IEnumerable<U> CastCollection<T, U>(this IList<T> items) where U : class
{
var collection = new List<U>();
foreach (var item in items)
{
if (item is U)
{
var newItem = item as U;
collection.Add(newItem);
}
}
return collection;
}
You would use it like this:
var myCollection = myObject.CastCollection<MyClassA, MyBaseClass>();
myCollection will be an IEnumerable<MyBaseClass> in this case.
Alternate solution: you could use interfaces and generics to get what you want.
public interface IMyClass
{
}
public class MyClassA : IMyClass
{
}
public class MyClassB : IMyClass
{
}
public class MyClassC : IMyClass
{
}
static void Main(string[] args)
{
var listA = new List<IMyClass>{new MyClassA{}, new MyClassA{}};
var listB = new List<IMyClass> { new MyClassB { }, new MyClassB { } };
var listC = new List<IMyClass> { new MyClassC { }, new MyClassC { } };
List<IMyClass> genericList = listA.Cast<IMyClass>().ToList();
}
Something like this will compile properly and also allow you to assign different lists of any types that implement the common interface, to the same variable (in this case genericList.
This cannot be done by casting the collection as a whole. However, you can cast the individual elements to a new collection. Look at LINQ's Cast<> extension method.
Is there any better way than the following?
Particularly, I want to replace Activator with something else.
public static List<T> ToList<T>(DataTable dt)
{
Type type = typeof(T);
List<T> list = new List<T>();
foreach (DataRow dr in dt.Rows)
{
object[] args = new object[1];
args[0] = dr;
list.Add((T)Activator.CreateInstance(type, args));
}
return list;
}
The first thing I want to mention is that you probably don't need a list. Odds are, an IEnumerable is enough. Even if you do need a list, it's trivial to convert an IEnumerable to a list.
With that in mind, this code is a nice generic way to accomplish it:
public static IEnumerable<T> ToEnumerable<T>(DataTable dt, Func<DataRow, T> translator)
{
foreach(DataRow dr in dt.Rows)
{
yield return translator(dr);
}
}
Hopefully you can see how re-usable this is. All you need to do is supply a function that knows how to convert an individual DataRow into your T type. That function might use Activator, but it doesn't have to. It might just use a normal constructor and set a few properties.
I don't really see any way to improve this code - why do you want to avoid Activator?
One option you could explore would be to create some sort of interface like this:
interface IFoo
{
void Initialize(DataRow dr);
}
And then implement this interface on any type that gets passed to this method. Then you would constrain your generic type parameter like this:
public static List<T> ToList<T>(DataTable dt)
where T : IFoo, new()
Then change the implementation of your method like this:
public static List<T> ToList<T>(DataTable dt)
where T : IFoo, new()
{
List<T> list = new List<T>();
foreach (DataRow dr in dt.Rows)
{
T t = new T();
t.Initialize(dr);
list.Add(t);
}
return list;
}
One thing I'd add to Andrew's answer is if you go that route you can (sorta) avoid the Activator class by constraining the generic method with a new() constraint.
public static List<T> ToList<T>(DataTable dt)
where T : IFoo, new()
{
...
foreach ( ... ) {
var foo = new T();
foo.Initialize(dataRow);
list.Add(foo);
}
...
}
The reason I say "sorta" is because C# actually just compiles that into an Activator.CreateInstance call at compile-time anyway. But it looks much cleaner.
I have class where the relevant part looks like
class C {
void Method<T>(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
How should I define the list so that the class compiles?
I want a list of type List<SomeClass<?>>, that is a list of objects of SomeClass where each object can have any type parameter. The Java ? construct allows this; what is the C# equivalent? If no such thing exists, is there a suitable workaround? (A List<object> would do but is terribly ugly.)
I don't think you can do this in C#... you would have to add the type parameter to the class:
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<SomeClass<T>> list = new List<SomeClass<T>>();
}
The other option would be to use an interface:
class C {
void Method<T>(T obj)
where T : ISomeClass {
list.Add(obj);
}
List<ISomeClass> list = new List<ISomeClass>();
}
To do what you want, you have two options.
You can use List<object>, and handle objects. This will not be typesafe, and will have boxing/unboxing issues for value types, but it will work.
Your other option is to use a generic constraint to limit to a base class or interface, and use a List<Interface>.
Unfortunately, there is no direct equivalent in C# 3.0 as generics are invariant.
You'll be able to do something like this in a graceful manner using C# 4.0 safe co/contra-variance feature.
To workaround it, you could inherit SomeClass<T> from a nongeneric base and create a List<BaseClass> instead.
If each instance of the class should hold only one type, you could make the class itself generic and set the type parameter there.
I don't know anything about Java's ? construct, but I think the following most closely preserves your existing syntax while also matching your description.
class SomeClass<T>
{
}
class C
{
void Add<T>(SomeClass<T> item)
{
Type type = typeof(SomeClass<T>);
if (!list.ContainsKey(type))
list[type] = new List<SomeClass<T>>();
var l = (List<SomeClass<T>>)list[type];
l.Add(item);
}
public void Method<T>(SomeClass<T> obj)
{
Add(obj);
}
readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
}
test it with the following:
class Program
{
static void Main(string[] args)
{
var c = new C();
var sc1 = new SomeClass<int>();
var sc2 = new SomeClass<String>();
c.Method(sc1);
c.Method(sc2);
c.Method(sc1);
c.Method(sc2);
}
}
Personally, I would do this where possible; move the generic parameter from the method, to the class.
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
If your generic list is a member, it stands to reason that the class should be constructed with this in mind. It is hard for us to suggest the best pattern without more usage context for the class.