Reputation: 10152
Not sure if it's possible, but I'd like to be able to populate a List<T>
based on what T
is. Presently, I have something like this (please forgive the generic names - it's for testing purposes):
public static class CollectionsClass
{
List<Object1> list1 = new List<Object1>();
List<Object2> list2 = new List<Object2>();
List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
if (list.GetType() == typeof(List<Object1>))
{
list.Add(new Object1());
}
else if (list.GetType() == typeof(List<Object2>))
{
list.Add(new Object2());
}
else if (list.GetType() == typeof(List<Object3>))
{
list.Add(new Object3());
}
else
{
// put out an error
}
}
}
}
While that code works, I'd like to shrink it by doing something like:
list.Add(new list.ObjectType());
I've been messing around with reflections and getting types all day, but I just can't seem to figure this one out.
Upvotes: 1
Views: 362
Reputation: 39013
Don't use dynamics, use generics:
static void Populate<T>(List<T> list, ...) where T: new()
{
...
for (int i=0; i<rndNum; i++)
list.Add(new T());
}
Upvotes: 4
Reputation: 22446
You can use a generic with a new
constraint to achieve this:
private static void PopulateList<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
The constraint is that the type T must provide a default constructor. If you want to add items to a List, you do not need the dynamic
keyword as you can specify List<T>
as parameter type directly.
If you cannot add a default constructor, you can also provide a creator function:
private static void PopulateList<T>(List<T> list, Func<int, T> creatorFunc,
int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(creatorFunc(i));
}
}
You call the method like this:
var lst = new List<MyObjectType>();
PopulateList<MyObjectType>(lst, x => new MyObjectType(x), 1, 7);
In this sample, the value of i
is provided to the creatorFunc that returns a new object of type MyObjectType
.
Upvotes: 1
Reputation: 1185
Use factory to extract the creation logic, reflection to get the correct type, and Activator to get the instance.
public static class TFactory
{
public static T Getmplementation<T>()
{
var typeName = typeof(T).Name;
var type = Type.GetType(typeName);
if (type != null)
return Activator.CreateInstance(type) as T;
else
throw new NotImplementedException(typeName);
}
}
Then,
List.Add(TFactory.GetImplmentation<'T>());
Upvotes: 1
Reputation: 44439
Sounds like you want a combination of generics and reflection.
First of all make it generic:
void Populate<T>(List<T> mylist)
Now you know the type of your list: it's T
.
All that is left is looping and creating instances of a particular type T
. For this you can use Activator.CreateInstance
:
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
With this sample code:
void Main()
{
Populate<Type1>(new List<Type1>());
Populate<Type2>(new List<Type2>());
}
void Populate<T>(List<T> mylist){
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
foreach(var item in mylist){
Console.WriteLine (item);
}
}
class Type1 { }
class Type2 { }
class Type3 { }
You get this output:
This will rely on reflection to create an instance of your object any assumes there is a public non-parameter constructor available (otherwise an exception will be thrown from the Activator
).
This is not quite desirable behaviour and I realized it as soon as I saw the other answers that use the where T : new()
constraint in their generic function: use this method over mine.
I'll still leave it in here for completeness though (at the very least it demonstrates a possible trap).
Upvotes: 1
Reputation: 14059
Try to use generic method:
public static class CollectionsClass
{
public static List<Object1> list1 = new List<Object1>();
public static List<Object2> list2 = new List<Object2>();
public static List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
}
Upvotes: 2
Reputation: 564363
Since you're already using dynamic
, you should be able to add method to handle this:
private static void AddToList<T>(List<T> list) where T : new()
{
list.Add(new T());
}
Given that, you can write:
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
AddToList(list);
}
}
Upvotes: 3