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);
Related
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();
}
}
ClassA, ClassB, ClassC and ClassD are all implementing IMyClass interface.
myObj is an instance of one of the classes.
private void setObj<T>()
{
myObj = mycollection.Single(w => w is T);
}
public void Switch()
{
if(myObj is ClassA)
{
setObj<ClassA>();
}
else if(myObj is ClassB)
{
setObj<ClassB>();
}
else if(myObj is ClassC)
{
setObj<ClassC>();
}
else if(myObj is ClassD)
{
setObj<ClassD>();
}
}
How can we refactor the Switch method, so that I have something like this:
public void Switch()
{
// How can we know from `myObj`, which class it is and rewrite
// the whole Switch method like this
// X = `ClassA`, `ClassB`, `ClassC` or `ClassD`
setObj<X>();
}
You cannot pass a generics type parameter as a variable in C#. However, you can get the type via reflection (myObj.GetType()) and pass that as a function parameter from your Switch() function to your setObj() function, which in turn can be compared in your lambda:
private void setObj(Type type)
{
myObj = Objects.Single(o => o.GetType() == type);
}
public void Switch()
{
Type setToThisType = myObj.GetType();
setObj(setToThisType);
}
make Switch a generic method too that accepts an object of type T
public void Switch<T>(T obj) where T : IMyClass
{
setObj<T>();
}
The where T : IMyClass statement ensures that you can only call Switch where obj is an instance of a class implementing IMyClass
void Example()
{
ClassA objA = new ClassA();
Switch(objA); //OK;
ClassX objX = new ClassX();
Switch(objX); //compile-time error since ClassX doesn't implement IMyClass
}
EDIT: after reading the title, I think you would need to have the parameter T obj in the Switch method.
Try using typeof(ClassA)
public void TypeTest(Type t)
{
if(t.Equals(typeof(ClassA))){
}
}
Here is my issue;
public class MyClass<T>
{
public void DoSomething(T obj)
{
....
}
}
What I did is:
var classType = typeof(MyClass<>);
Type[] classTypeArgs = { typeof(T) };
var genericClass = classType.MakeGenericType(classTypeArgs);
var classInstance = Activator.CreateInstance(genericClass);
var method = classType.GetMethod("DoSomething", new[]{typeof(T)});
method.Invoke(classInstance, new[]{"Hello"});
In the above case the exception I get is: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
If I try to make the method generic it fails again with an exception:
MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.
How should I invoke the method?
You are calling GetMethod on the wrong object. Call it with the bound generic type and it should work. Here is a complete sample which works properly:
using System;
using System.Reflection;
internal sealed class Program
{
private static void Main(string[] args)
{
Type unboundGenericType = typeof(MyClass<>);
Type boundGenericType = unboundGenericType.MakeGenericType(typeof(string));
MethodInfo doSomethingMethod = boundGenericType.GetMethod("DoSomething");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { "Hello" });
}
private sealed class MyClass<T>
{
public void DoSomething(T obj)
{
Console.WriteLine(obj);
}
}
}
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> ?
I have the following C# test code:
class MyItem
{
MyItem( int a ) {}
}
class MyContainer< T >
where T : MyItem, new()
{
public void CreateItem()
{
T oItem = new T( 10 );
}
}
Visual Studio can't compile it, the error is at line where 'new' is used:
'T': cannot provide arguments when creating an instance of a variable type
Is it possible in C# to create an object of generic type with non-parameterless constructor? It's no problem to do such thing in C++ templates, so i'm very curious why i can't do same thing in C#. Maybe some additional 'where' is required or syntax is different?
C#, and VB.Net for that matter, do not support the notion of constraining a generic to have a constructor with specific parameters. It only supports constraining to have an empty constructor.
One work around is to have the caller pass in a factory lambda to create the value. For instance
public void CreateItem(Func<int,T> del) {
T oItem = del(10);
}
Call site
CreateItem(x => new SomeClass(x));
It can be done with reflection:
public void CreateItem()
{
int constructorparm1 = 10;
T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T;
}
But there is no generic constraint to ensure that T implements the desired constructor, so I wouldn't advise doing this unless you are careful to declare that constructor in every type that implements the interface.
There's no such generic constraint, so it's not possible directly (this is a CLR limitation). If you want this, you have to provide a factory class (which has a parameterless constructor), and pass it as a second generic type parameter.
IMO, the best approach here is an initialize method, i.e.
interface ISomeInterface {
void Init(int i);
}
class Foo : ISomeInterface {
void ISomeInterface.Init(int i) { /* ... */ }
}
static class Program {
static T Create<T>(int i) where T : class, ISomeInterface, new() {
T t = new T();
t.Init(i);
return t;
}
static void Main() {
Foo foo = Create<Foo>(123);
}
}
However, you can do what you want with Expression (but without compile-time support):
using System;
using System.Linq.Expressions;
class Foo {
public Foo(int i) { /* ... */ }
}
static class Program {
static T Create<T>(int i) {
return CtorCache<T>.Create(i);
}
static class CtorCache<T> {
static Func<int, T> ctor;
public static T Create(int i) {
if (ctor == null) ctor = CreateCtor();
return ctor(i);
}
static Func<int, T> CreateCtor() {
var param = Expression.Parameter(typeof(int), "i");
var ci = typeof(T).GetConstructor(new[] {typeof(int)});
if(ci == null) throw new InvalidOperationException("No such ctor");
var body = Expression.New(ci, param);
return Expression.Lambda<Func<int, T>>(body, param).Compile();
}
}
static void Main() {
Foo foo = Create<Foo>(123);
}
}
Note that this caches and reuses the delegate for performance.
One pattern I use is to have the constrained class implement an interface which defines an Init method with the appropriate signature:
interface IMyItem
{
void Init(int a);
}
class MyItem : IMyItem
{
MyItem() {}
void Init(int a) { }
}
class MyContainer< T >
where T : MyItem, IMyItem, new()
{
public void CreateItem()
{
T oItem = new T();
oItem.Init( 10 );
}
}