Generic List created at runtime - c#

i neeed something like this in C#.. have list in class but decide what will be in list during runtime
class A
{
List<?> data;
Type typeOfDataInList;
}
public void FillData<DataTyp>(DataTyp[] data) where DataTyp : struct
{
A a = new A();
A.vListuBudouDataTypu = typeof(DataTyp);
A.data = new List<A.typeOfDataInList>();
A.AddRange(data);
}
Is this possible to do something like this ?

class A<T>
{
public readonly List<T> Data = new List<T>();
public Type TypeOfDataInList { get; private set; }
public A()
{
TypeOfDataInList = typeof(T);
}
public void Fill(params T[] items)
{
data.AddRange(items);
}
}
If you don't know the type or have multiple objects of different types, declare an instance of A like this:
A<object> myClass = new A<object>();
myClass.Fill(new object(), new object());
Otherwise if you know the type, you can do this:
A<int> myInts = new A<int>();
myInts.Fill(1, 2, 5, 7);

Yes.
class A
{
IList data;
Type typeOfDataInList;
}
public void FillData<T>(T[] data) where T : struct
{
A a = new A();
A.typeOfDataInList = typeof(T);
A.data = new List<T>(data);
}
It would be better to make the A class generic:
class A<T>
{
IList<T> data;
Type typeOfDataInList;
}
public void FillData<T>(T[] data) where T : struct
{
A<T> a = new A<T>();
a.typeOfDataInList = typeof(T);
a.data = new List<T>(data);
}

You are going to need to use reflection to instantiate an IList<T> where T is not known until runtime.
See the following MSDN article, which explains it better than I could (scroll down to the section on how to construct a generic type):
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
Here is a short example:
Type listType = typeof(List<>);
Type runtimeType = typeof(string); // just for this example
// assert that runtTimeType is something you're expecting
Type[] typeArgs = { runtimeType };
Type listTypeGenericRuntime = listType.MakeGenericType(typeArgs);
IEnumerable o = Activator.CreateInstance(listTypeGenericRuntime) as IEnumerable;
// loop through o, etc..

You might want to consider a generic class:
public class A<T> where T : struct
{
public List<T> data;
public Type type;
}
public void FillData<DataType>(DataType[] data) where DataType : struct
{
A<DataType> a = new A<DataType>();
a.data = new List<DataType>();
a.AddRange(data);
}

System.Collections.Generic.List<T> ?

Related

C# How To Initialize a generic Class with a type variable

disclaimer I'm a newbie in understanding Reflection.
abstract class BaseClass<T>
{
public abstract T Value { get; }
public virtual bool CheckValue(string input)
{
return true;
}
}
class NotBaseClassA : BaseClass<string>
{
public override string Value { get => "Yes";}
public override bool CheckValue(string input)
{
return 1 == 2;
}
}
class NotBaseClassB : BaseClass<int>
{
public override int Value { get => 1; }
}
class ManyBaseClasses
{
public NotBaseClassB notBaseClassB;
public NotBaseClassA notBaseClassA;
}
class Programm
{
public void Main()
{
foreach (PropertyInfo pi in typeof(ManyBaseClasses).GetProperties())
{
string input = Console.ReadLine();
//Get the generic type of the propertyInfo
//BaseClass<type> bt = new BaseClass<type>();
//Instantiate BaseClass not as a var So I can do
//BaseClass.CheckValue(input)
}
}
}
I'm just trying to do like the title says. So i saw this answer but the answer returns a 'var' but I cant call my CheckValue() function from a type var. (Or i dont think I can?). What i Need is to Instantiate my BaseClass<> with the correct type from a type variable and not as a var, as a proper BaseClass obj so i can then call my functions.
Edit 1 : i've already managed to get the generic type in the variable by doing something like that
public static System.Type GetBaseClassType(this System.Type type)
{
System.Type[] types = new System.Type[]{ };
while (type != null && type != typeof(object) || types.Length == 0)
{
types = type.GetGenericArguments();
if (types.Length > 0)
{
return types[0];
}
type = type.BaseType;
}
return null;
}
The base class is not relevant in this case, as it's abstract, so you actually want to instantiate the derived class.
All you need to do to create it is
Activator.CreateInstance(pi.PropertyType)
Then you will need to use reflection on that result to call CheckValue, because there is no common base type or interface.
It might be easier to extract the non-generic code into a BaseBaseClass which is not generic, which means you don't need reflection for the second step.
abstract class BaseBaseClass
{
public virtual bool CheckValue(string input)
{
return true;
}
}
abstract class BaseClass<T> : BaseBaseClass
{
public abstract T Value { get; }
}
Then you can just do
((BaseBaseClass) Activator.CreateInstance(pi.PropertyType)).CheckValue(someInput)
I've done that before, but it was a long time ago. You have to create instance via reflection and call the method via reflection.
foreach (PropertyInfo pi in typeof(ManyBaseClasses).GetProperties())
{
string input = Console.ReadLine();
//Get the generic type of the propertyInfo
var propType = pi.Type;
Type[] typeArgs = { propType };
var genType = d1.MakeGenericType(typeArgs);
//BaseClass<type> bt = new BaseClass<type>();
object bt = Activator.CreateInstance(genType);
//Instantiate BaseClass not as a var So I can do
//BaseClass.CheckValue(input)
MethodInfo method = typeof(bt).GetMethod("CheckValue"));
method.Invoke(bt, new[] { input });
}

Cast to Type with reflection without generic argument

I have an issue which involves casting to different Types
I have a class which is a wrapper, which contains an inner wrapper which contains T here is the structure:
public class Wrapper
{
public readonly Guid Foo;
public Wrapper(Guid foo)
{
Foo = foo;
}
}
public class Wrapper<T> : Wrapper
{
public readonly InnerWrapper<T> InnerWrapper;
public Wrapper(Guid foo, InnerWrapper<T> innerWrapper)
: base(foo)
{
InnerWrapper = innerWrapper;
}
}
public class InnerWrapper<T>
{
public readonly Guid Bar;
public readonly T Content;
public InnerWrapper(T content, Guid bar)
{
Content = content;
Bar = bar;
}
}
In another part of the code I have a List<Wrapper>. notice that is a list of wrapper not a list of wrapper<T> which means that T can be any class.
when this translates is expected to have something like
{
wrapper<Class1>,
wrapper<Class2>
}
and so on.
At some point in the code there is a "helper class" which contains the object as object type and the Type
public class Helper
{
public readonly object Obj;
public readonly Type Type;
public Helper(object obj, Type type)
{
Obj = obj;
Type = type;
}
}
And here is where my problem begins, I created a helper method to convert from List<Helper> to List<Wrapper> and it does it, but the inner object is type object instead of being the actual type.
And i have no clue of how to convert from object to the actual type without using generics, and as T can be multiples types I cannot use them.
This is the helper classs
public static class HelperExtensions
{
public static T CastTo<T>(this object o) => (T)o;
public static List<Wrapper> ToWrapper(this IEnumerable<Helper> helperList)
{
List<Wrapper> wrapperResponseList = new List<Wrapper>();
foreach (var help in helperList)
{
// doesn't work either var typedValue = Convert.ChangeType(help.Obj, help.Type);
var methodInfo = typeof(HelperExtensions).GetMethod(nameof(CastTo), BindingFlags.Static | BindingFlags.Public);
var genericArguments = new[] { help.Type };
var genericMethodInfo = methodInfo?.MakeGenericMethod(genericArguments);
var typedValue = genericMethodInfo?.Invoke(null, new[] { help.Obj });
var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());
wrapperResponseList.Add(wrapper);
}
return wrapperResponseList;
}
//This one called individually does the work properly
public static Wrapper<T> BuildWrapper<T>(this T obj, Guid foo, Guid bar)
{
InnerWrapper<T> inner = new InnerWrapper<T>(obj, bar);
return new Wrapper<T>(foo, inner);
}
}
to show the code here I also Created a test class
public class Placeholder
{
public Guid Value { get; }
public Placeholder(Guid value)
{
Value = value;
}
}
so when I call
Placeholder placeholder = new Placeholder(Guid.NewGuid());
Helper helper1 = new Helper(placeholder, placeholder.GetType());
var result = new List<Helper> { helper1 }.ToWrapper();
It generates a List<Wrapper> but instead of wrapper<T> it is generating Wrapper<Object>
Any idea how can I cast it properly?
I also created a fiddle https://dotnetfiddle.net/pz3JDz which contains all the needed code to test.
Thanks In advance for your help.
The local variable typedValue is declared with var and because genericMethodInfo?.Invoke(...) returns the reply of the type object, the type of that local variable typedValue will be object. After that you call the generic method Wrapper<T> BuildWrapper<T>(this T obj, ...) here since the type of typedValue is object the type of T is will also be object, therefore it will return Wrapper<object>.
To solve it instead of this:
var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());
Do this:
var buildWrapperMethodInfo = typeof(HelperExtensions).GetMethod(nameof(BuildWrapper), BindingFlags.Static | BindingFlags.Public);
var buildWrapperGenericMethodInfo = buildWrapperMethodInfo?.MakeGenericMethod(genericArguments);
var wrapper = buildWrapperGenericMethodInfo?.Invoke(null, new[] { typedValue, Guid.NewGuid(), Guid.NewGuid() });
And then add the type cast here:
wrapperResponseList.Add((Wrapper)wrapper);
Simplifying the call to directly retrieve the object from the BuildWrapper<T> is possible.
You can do the following. You can obviously reformat for error check but you get the idea.
var wrapperGeneric = typeof(HelperExtensions).GetMethod("BuildWrapper").MakeGenericMethod(new[] { help.Type}).Invoke(this,help.Obj)

Convert array type to singular

In C# is it possible to convert an array type to singular - for use with Activator.CreateInstance. Take this for example:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
// possibly convert type here? (from array to singular - type[] to type)
Debug.WriteLine($"{type}");
objects.Add(Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}
Gets the following output:
If I understand your Question right you might want something like this using Type.GetElementType() via reflection.
static void Main(string[] args)
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
var typeInstance = type.GetElementType();
if (typeInstance != null)
{
Debug.WriteLine($"{typeInstance}");
objects.Add(Activator.CreateInstance(typeInstance));
}
else
{
objects.Add(Activator.CreateInstance(type));
}
}
}
public class ExampleClass
{
public int X;
public int Y;
}
If I understand your question correctly, you want to get the base-type of an array, right? That should be quite easy with the IsArray property of the type, simply check each entry of your list like this:
private static Type GetTypeOrElementType(Type type)
{
if (!type.IsArray)
return type;
return type.GetElementType();
}
Btw, if you want to create a new Array of that specific type, you can use Array.CreateInstance instead of Activator.CreateInstance
Found this works:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
Debug.WriteLine($"{type}");
objects.Add(type.IsArray
? Activator.CreateInstance(type, 1)
: Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}

Is there a way to invoke a templated class on an anonymous type?

Here's some code to give the idea.
public class C<T> { }
public class X {
void M() {
var V = new { W = 1 };
var X = new C<V>(); // illegal
}
}
So V is a variable of an anonymous type and I would like to instantiate class C with V as its argument. This requires a type argument, which I cannot supply.
This questions is similar but the answer is not much help in my case: Why can't I instantiate a generic class inferring types from anonymous objects?
The question behind the question is that I'm trying to do what IEnumerable can do.
Should have made it clear: I would really prefer not to do this by manipulating object or Type because you lose the benefits of strong typing and Intellisense.
For anyone interested, the project that needs this is described here: http://www.andl.org/2016/07/andl-net-making-progress/.
You can use type inference if you have a factory method:
public class C<T>
{
public C(T t)
{
// ...
}
}
public static class Factory
{
public static C<T> Create<T>(T t)
{
return new C<T>(t);
}
}
public class Thing
{
void Foo()
{
var x = new { y = "z" };
//var thing = new C(x); - doesn't work, you need to specify the generic parameter
var thing = Factory.Create(x); // T is inferred here
}
}
You can't do that since V is instance of anonymous type, not a type name itself.
You can create this type dynamically (assuming parameterless constructor in C<>):
var X = typeof (C<>)
.MakeGenericType(V.GetType())
.GetConstructor(Type.EmptyTypes)
.Invoke(new object[0]);
You need a type, you can use pass object as a type.
Sample code:
public class C<T>
{
public T _t { get; set; }
public C(T t)
{
_t = t;
}
public void TestMethod()
{
Console.WriteLine(_t.ToString());
}
}
public class X
{
public void M()
{
var V = new { W = 1 };
var X = new C<object>(V); // everything is an object.
X.TestMethod();
}
}

Pass a dynamic type

I am aware of passing dynamic types with reflection but with the following class structure am having a little difficulty; where my calling class would be instantiating another class and calling a method on it's base class passing the method a dynamic type.
public class MainClass
{
// var genericClass = new GenericClass();
// genericClass.SomeMethod<T>();
var myDynamicType = Type.GetType(FullyQualifiedNamespace + className);
Activator.CreateInstance(myDynamicType);
}
public class GenericClass : GenericBase
{
}
public abstract class GenericBase
{
private readonly List<IMyInterface> myList = new List<IMyInterface>();
public void SomeMethod<T>() where T : IMyInterface, new ()
{
myList.Add(new T());
}
}
You can change the method signature of SomeMethod<T>() with SomeMethod(Type t).
public void SomeMethod(Type t)
{
if (t.GetInterfaces().Contains(typeof(IMyInterface)) &&
t.GetConstructor(Type.EmptyTypes)!=null)
{
var obj=(IMyInterface)Activator.CreateInstance(t);
myList.Add(obj);
}
}
You have two options. The first involves modifying the SomeMethod<T> method to be non-generic or adding a non-generic overload:
public void SomeMethod(Type t) {
var myInterface = (IMyInterface)Activator.CreateInstance(t);
myList.Add(myInterface);
}
public void SomeMethod<T>() where T : IMyInterface, new ()
{
SomeMethod(typeof(T));
}
Then call is as follows:
var myDynamicType = Type.GetType(FullyQualifiedNamespace + className); //I assume this is the type that you want to use as the generic constraint 'T' of SomeMethod<T>
var genericClass = new GenericClass();
genericClass.SomeMethod(myDynamicType);
Alternatively, you can leave the SomeMethod<T> method alone and invoke the method via reflection:
var myDynamicType = Type.GetType(FullyQualifiedNamespace + className); //I assume this is the type that you want to use as the generic constraint 'T' of SomeMethod<T>
var genericClass = new GenericClass();
var method = typeof(GenericClass).GetMethod("SomeMethod").MakeGenericMethod(myDynamicType);
method.Invoke(genericClass);

Categories

Resources