Is it possible to create a method which returns a type and use it?
for example, assume I have a Person type and Object parameter.
As you probably know, If we want to cast our Object parameter, we can write:
object param;
((Person)param).executePersonMethod();
My question is how can I write a method which return Person type and use it instead the concrete Person cast - I want write something like this:
public Type GetPersonType()
{
//return here type of person
}
and then use
((GetPersonType())param).executePersonMethod();
Is it possible?
If yes, how?
You can use interface.
((IPerson)param).executePersonMethod();
each type of person must be an IPerson
and in IPerson you declare executePersonMethod()
You can also use dynamic for this.
Note that using dynamic will skip any compile time checking whether that method exists and will throw an exception at runtime if it doesn't.
Due to this risk, I would only do this if I have no other choice, but it's good to know that the option exists:
dynamic d = param;
d.executeWhateverMethodHereWithoutCompileTimeChecking();
Yes you can. There is a new type called dynamic which will avoid static type check during compilation.
public dynamic GetPersonOrObjectWhichHasExecutePersonMethod()
{
//return not the type but the object itself
return new Person();
}
public class Person
{
public void executePersonMethod()
{
// do something
}
}
// this is how you invoke it
public void ExecuteMethod()
{
dynamic obj = GetPersonOrObjectWhichHasExecutePersonMethod();
obj.executePersonMethod();
}
Maybe you can use something like that:
Convert.ChangeType(param, typeof(Person));
It would returns param as a Person.
You cannot execute methods on a Type, you can only execute methods on an instance of a particular Type. If I am understanding correctly, you should be able to use the answer #LavG gives to:
return not the type but the object itself from the GetPersonType method
Edit: As per your comment:
Here are some SO QA which will help you get the Type using fully
qualified namespace and other techniques:
How to get the type for a class by sending just the name of the class instead of the class itself as the parameter?
Type.GetType("namespace.a.b.ClassName") returns null
Here is how to generate a class from the given Type at run time:
generating a class dynamically from types that are fetched at runtime
Use
TypeOf()
Example :
if (data.GetType() == typeof(Personne))
return (Personne)data;
else
return new Personne();
After, check your object is not null to know if it's ok
Although you can use Generic as a better option, however it is possible using Type Convertor in combination with reflection:
Type type = GetPersonType();
var converted = Convert.ChangeType(param, type);
converted
.GetType()
.GetMethod(/*your desired method name in accordance with appropriate bindings */)
.Invoke(converted, /* your parameters go here */);
Related
I am trying to create an instance of a generic class but my Type T of the generic class, i have gone through this link
http://msdn.microsoft.com/en-us/library/w3f99sx1(v=vs.110).aspx
but i couldn't find what i was looking for
i have this code
public class MyClass<T>
{
public T prop { get; set; }
}
and i have the type stored in string
the type
string typeString = "System.String";
now i want to use this type in myclass this way
Type xt = new Type.GetType(typeString);
MyClass<xt> obj = new MyClass<xt>();
but that just unidentified type xt
so what do i do!
The section Constructing an Instance of a Generic Type in the link provided covers this exact case.
In your case you would need write
Type typeArgument = Type.GetType(typestring);
Type constructed = typeof(MyClass<>).MakeGenericType(typeArgument);
object instance = Activator.CreateInstance(constructed);
However, the use cases of this techniques are far from common. You should try as much as possible to provide type information at compile-time. That is, try not to rely on Reflection to create your objects. Generics methods are especially useful for such cases.
The method Type.GetType(someString) gets the type at runtime, but generics class must be evaluated at compiled time. Between the <> symbols you need to specify the type itself and not an instance of the object Type. Something like this must work:
MyClass<String> obj = new MyClass<String>();
Thanks,
var type = data.ClientBaseObject.GetType();
var newClientObject = GetDataContextedObject(type, data.ClientBaseObject);
private object GetDataContextedObject(Type type, object jobObject)
{
switch (type.Name.ToUpper())
{
case "JOBNUMBER":
{
return GetObjectFromDataContext<JobNumber>(jobObject);
}
case "NA_HEADER":
{
return GetObjectFromDataContext<NA_Header>(jobObject);
}
}
return null;
}
private object GetObjectFromDataContext<T>(object jobObject) where T: class, IJobID
{
var newObject = jobObject as T;
return _dc.GetTable<T>().FirstOrDefault(j => j.JobID == newObject.JobID);
}
In the above code, I am wondering if there is a way I can make the GetObjectFromDataContext into GetObjectFromDataContext<type>, instead of having to get the type.Name for each class and creating a case for each one. Can this be done?
Let me know if the question is not clear.
You can write it this way:
private object GetDataContextedObject<T>(object jobObject)
{
return GetObjectFromDataContext<T>(jobObject);
}
Do all of the allowable types implement a common interface? If so, then yes; change GetObjectFromDataContext to accept the base type as a generic argument.
However, a generic argument must be determined at compile time. Otherwise how would the feature provide type safety? You may as well just be passing everything around as an object at that point.
EDIT: Per your update.
I you must be able to pass in a Type parameter at runtime, then no, you can't do what you want. Since this is all occurring at runtime you will have to selectively call the generic version. You cannot use the overload of GetTable that takes a Type argument for the same reason; you'll need a cast as it returns an ITable.
Do you really need to do this dynamically using a Type parameter?
I'm trying to create an instance of specified Type whatever user wants to have. For a quick illustration of my purpose please see the code below:
static void Main(string[] args)
{
object o = GetInstance(typeof(int));
Console.WriteLine("Created type: {0}", o.GetType().FullName);
}
public static object GetInstance(Type t)
{
Console.WriteLine("Creating instance of {0}", t.FullName);
return Activator.CreateInstance(t);
}
The problem is Activator.CreateInstance() returns object by default. There is also an overload of this method like T Activator.CreateInstance<T>() which is parameterless and returns the type you specify as T.
However, the problem is T should be hard-coded while calling this method and thus should be a fixed value. I am trying to create an instance of desired class and return it as its type.
Right now if you use this method you should write something like:
int i = GetInstance(typeof(int)) as int
I'm trying to reduce this to:
int i = GetInstance(typeof(int))
Is there a way that I can do casting inside the GetInstance and get rid of that as int repetition? By this way, my return type (and also the type I cast the object to) will be unknown at compile time.
Seemed impossible by design to me but I'd really appreciate if you figure it out.
EDIT: Where I'm stuck is e.g. while you're casting, you can do return (T) result if you are in a generic method, but you can't do Type t = ...; return (t) result this doesn't work. You cannot cast to a type which is passed to you as a parameter which is not known at compile time.
Follow a known pattern
This is not a new problem. It is a problem facing any API that allows type-specific return values. For example, a JSON parsing library like Newtonsoft (which is, to wit, the single most popular .NET package downloaded by .NET programmers in 2019) must be able to parse a string and return a type-specific object, which may or may not be known at compile time. It might make sense to follow their example.
Newtonsoft exposes three ways to specify the type when deserializing. You could do as you are currently doing:
//Cast required
var result = JsonConvert.DeserializeObject(text, typeof(MyType)) as MyType;
You can use a generic method:
//No cast required, but you have to hardcode a type as a type parameter
var result = JsonConvert.DeserializeObject<MyType>(text);
Or you can use an instance as a template, which is great for anonymous types, although you can use it with non-anonymous classes as well. This one works via generic type inference:
//No cast required and no need to specify type; the type is inferred from the argument
var result = JsonConvert.DeserializeAnonymousType(text, new MyType());
Here's how you'd do it:
So for you to make this work, your code might look like this:
public object GetInstance(Type type)
{
return Activator.CreateInstance(type);
}
int i = GetInstance(typeof(int)) as int;
public T GetInstance<T>()
{
return Activator.CreateInstance<T>();
}
int i = GetInstance<int>();
public T GetInstance<T>(T template)
{
return Activator.CreateInstance<T>();
}
int i = GetInstance(0);
If you do it this way, it's hard to imagine any programmer would have trouble using your library, as the approach should already be familiar to them.
Actually you could write GetInstance like this:
static T GetInstance<T>()
{
return Activator.CreateInstance<T>();
}
And use it:
int j = GetInstance<int>();
This might help you to create instance of desired type:
public class ConcreteFactory<T> : AbstractFactory<T>
{
public override T CreateInstance(string typeName,params object[] parameters)
{
var path = Assembly.GetExecutingAssembly().CodeBase;
var assembly = Assembly.LoadFrom(path);
var type = assembly.GetTypes().SingleOrDefault(t => t.Name == typeName);
return (T)Activator.CreateInstance(type, parameters);
}
}
Key here is generic type T can be used to cast the created instance, this can be used as a template to create instance of any type with parameterized constructor
I have a method like this,
public List<T> Test<T>()
{
// do something.
}
I don't know what is T and dont have. But I have type of T as TYPE.
for example:
class Person
{
}
var type = typeof(Person);
I don't have Person. Person is keeping at the type object.
How can I use the test method ?
var list = Test<type>(); // It gives an error like this. I must use the type object.
You can use the MakeGenericMethod method from MethodInfo:
MethodInfo info = this.GetType().GetMethod("Test").MakeGenericMethod(type);
object result = info.Invoke(this, null);
This is assuming you call the method inside the same type that defines Test. If you call it from somewhere else, use typeof(ClassThatDefinesTest) instead of this.GetType(), and the instance of this class instead of this.
If typeof(T) is all you really needed, then you can refactor it to:
public void Test(Type t)
{
// do something.
}
And call it like:
Test(type);
If this won't work for you, I recommend Botz3000's solution using MakeGenericMethod.
You could expose both Test<T>() and Test(Type) and then have one call the other, (either with MakeGenericMethod or typeof(T)) depending on whether you need the static type or simply the runtime type. That way your callers don't need to know which of the two you need.
You have pass the Class name to it. Please refer to the following MSDN,
http://msdn.microsoft.com/en-us/library/twcad0zb(v=vs.100).aspx
As said #Botz3000 you can use MakeGenericMethod() method. But another solution could be use the dynamic keyword and the CreateInstance() method from Activator class:
public void Test(Type type)
{
dynamic myVariable = Activator.CreateInstance(type);
// do something, like use myVariable and call a method: myVariable.MyMethod(); ...
}
You call it like this:
Test<Person>();
I have a factory defined like so :
public IPopulator CreatePopulator<T>(ReportItem Item) where T : IReportElement
{
if (typeof(T) == typeof(BarChartElement))
{
return BarChartPopulator.Create(Item);
}
else
{
throw new NotSupportedException(string.Format("Type: {0} is not suppported by {1}", typeof(T).Name, this.GetType().Name));
}
}
In the class that calls this method I have a variable like this:
IReportElement MyElement { get; set; }
Assuming MyElement is instantiated to a type that implements IReportElement, How can I call my factory using this variable ?
I have tried
Type VariableType = MyChartElement.GetType();
PopulatorFactory.CreatePopulator<VariableType>(new Chart());
And
PopulatorFactory.CreatePopulator<MyVariable.GetType()>(new Chart());
I could write a switch statement but I feel like there should be some way for me to pass my type. Is this possible ?
You can't use variables as generic arguments like that. The only way they can provide type safety is if the type is known at compile time.
Factory methods as you describe to tend to be implemented as switch statements, and there is nothing inherently wrong with that. You can pass an enumerated type to your factory method which will in turn return an instance of a type that implements IReportElement.
I don't quite get what you are trying to accomplish here anyway. Your generic factory method is checking the type of the argument. If you have to check the type then, well, it ain't generic anymore, so what's the point?
Perhaps you could go into a bit more depth as to what problem you are actually trying to solve with this code. There may be a better alternative that you have not yet considered.
If you are working with a library that cannot change to be like #Dan Bryant suggested, something like this ought to work.
typeof (PopulatorFactory)
.GetMethod("CreatePopulator")
.GetGenericMethodDefinition()
.MakeGenericMethod(new[] {myVariable.GetType()})
.Invoke(null, new object []{new Chart ()});