Maybe it is pretty simple, but I'm not in use with the type Type
and it's uses.
Say I want to create a List<T>
either with T
=Double
or T
=UInt32
, depending on the result of some function, say public static Type CheckType(String input);
In code:
Type t = Program.CheckType(someInput); // it returns typeof(Double) or typeof(UInt32)
if (t == typeof(Double))
List<Double> l = new List<Double>();
else
List<UInt32> l = new List<UInt32>();
I know the above code won't compile because I'm letting l
to have two different meanings (a list of double and a list of unsigned int)... So it leads to my question:
- Is there a way to avoid the
if
in the above code?
Something similar to this:
Type t = Program.CheckType(someInput);
List<t> l = new List<t>(); // I know this won't compile either...
I mean, that would generically instantiate a generic List...
Thank you in advance!
EDIT:
This is NOT a duplicate of the marked question for only one reason: Double
and UInt32
are not Anonymous types! The question, here, is how to determine the type of some input data (which will be Type T
=typeof(Double)
or Type T
=typeof(UInt32)
, for example) and, thus, create a generic SampleClass<T>
based on that input data type, T
!
In other words: determine some Type T
in the runtime and, then, instantiate a generic type with the determined type T
. Sorry if I didn't make that clear before...
PS: I used List<T>
as an example for SampleClass<T>
.
You can't type the list as generic, since you don't know the type parameter, but you can create a List instance at runtime.
Type t = Program.CheckType(someInput);
Type listType = typeof(List<>).MakeGenericType(t);
IList list = (IList) Activator.CreateInstance(listType);
If you try to add an object of the incorrect type, you will get an exception, so this approach has an advantage over using a collection like ArrayList
, or List<object>
There's no real reason to use generics in such instances. Since the generic argument isn't known at compile time the compiler can't verify whether or not the objects you're trying to add or remove are appropriate for that list.
If at all possible, it's best to avoid this situation entirely, possibly through making the method that this code is in generic itself.
If that's not possible, it's probably better to just use the non-generic ArrayList
or a List<object>
, because using a generic list in this context will add a lot of extra work for no extra help.
MakeGenricType might work
Using Reflection to set a Property with a type of List<CustomClass>
Type type = Program.CheckType(someInput);
IList list = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
object obj = Activator.CreateInstance(type);
list.Add(obj);
Type t = Program.CheckType(someInput);
var l = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t));
I would go for a generic Histogram<T>
but not try to hold both types in the same variable, unless you want to just have a IDictionary
variable.
Here is an example with using the histogram with double
types:
class Program
{
static Random rnd=new Random();
static void Main(string[] args)
{
Historgram<double> hist=new Historgram<double>();
for(int i=0; i<1000; i++)
{
double x=Math.Round(rnd.NextDouble(), 1);
hist.Add(x);
}
//double[] values=hist.Values;
Console.WriteLine("Histogram");
Console.WriteLine("{0,12} {1,12}", "Value", "Quantity");
for(int i=0; i<=10; i++)
{
double x=(i/10d);
Console.WriteLine("{0,12} {1,12}", x, hist[x]);
}
Console.ReadLine();
}
with result
Histogram
Value Quantity
0 52
0.1 97
0.2 117
0.3 98
0.4 93
0.5 110
0.6 97
0.7 94
0.8 98
0.9 93
1 51
and the code:
public class Historgram<T>
{
Dictionary<T, int> bins;
public Historgram()
{
this.bins=new Dictionary<T, int>();
}
public void Add(T value)
{
if(bins.ContainsKey(value))
{
bins[value]++;
}
else
{
bins.Add(value, 1);
}
}
public void Remove(T value)
{
if(bins.ContainsKey(value))
{
bins[value]--;
if(bins[value]==0)
{
bins.Remove(value);
}
}
}
public int this[T x]
{
get
{
if(bins.ContainsKey(x))
{
return bins[x];
}
else
{
return 0;
}
}
set
{
if(bins.ContainsKey(x))
{
bins[x]=value;
}
else
{
bins.Add(x, value);
}
}
}
public bool ContainsValue(T value) { return bins.ContainsKey(value); }
public int Count { get { return bins.Count; } }
public T[] Values { get { return bins.Keys.ToArray(); } }
public int[] Quantities { get { return bins.Values.ToArray(); } }
}