I have a bunch of classes that inherit from a single class. I'm using reflections to access the classes, since the ones that will be accessed will change in runtime.
But I am having some trouble when trying to invoke a method declared at superclass.
Here is my parent class:
public class ParentClass {
public ParentClass (Type type) {
}
public string method0String () {
return string;
}
public void method1Void (string) {
}
}
Here is my child class:
public class ChildClass : ParentClass {
public ParentClass () : base(typeof(ChildClass)) {
}
}
Here is the abstract class code where I cast the methods:
Type childType = Type.GetType(className[i]);
ConstructorInfo childConstructor = childType.GetConstructor(new Type[0]);
object childObject = null;
childObject = childConstructor.Invoke(childObject, new object[0]);
MethodInfo parentMethod0String = childType.GetMethod("method0String");
MethodInfo parentMethod1Void = childType.GetMethod("method1Void");
parentMethod1Void.Invoke(childObject, new object[]{argString});
object finalString = parentMethod0String.Invoke(childObject, new object[0]);
The MethodInfos are always null, which causes this error when I try to invoke them:
System.NullReferenceException: Object reference not set to an instance of an object
I haven't found anyway around this.
Basically, I just need to invoke a super method using the child as the dynamic object. How can I achieve this?
#Edit
After #nvoigt answer, my code looks like this:
Type childType = Type.GetType(className[i]);
object childObject = Activator.CreateInstance(childType);
Type parentType = Type.GetType("ParentClass");
MethodInfo parentMethod0String = parentType.GetMethod("method0String");
MethodInfo parentMethod1Void = parentType.GetMethod("method1Void");
parentMethod1Void.Invoke(childObject, new object[]{argString});
object finalString = parentMethod0String.Invoke(childObject, new object[0]);
And the error is a little different:
System.Reflection.TargetException: Object does not match target type.
You can do it this way:
namespace StackOverFlowTest
{
using System;
class BaseClass
{
public int BaseClassMethod(int x)
{
return x * x;
}
}
class DerivedClass : BaseClass
{
}
class Program
{
static void Main()
{
var derivedType = typeof(DerivedClass);
var baseType = typeof(BaseClass);
var method = baseType.GetMethod("BaseClassMethod");
var derivedInstance = Activator.CreateInstance(derivedType);
var result = method.Invoke(derivedInstance, new object[] { 42 });
Console.WriteLine(result);
Console.ReadLine();
}
}
}
Related
I have 2 class which has a different constraint, and I want to create obj for them conditionally in a generic function. Example below.
public class Foo1<T>
where T : class, Interface1, new()
{
// do sth...
}
public class Foo2<T>
where T : class, Interface2, new()
{
//do sth...
}
public static void Create<T>()
{
if(typeof(Interface1).IsAssignableFrom(typeof(T))
{
var obj = new Foo1();
//...
} else if (typeof(Interface2).IsAssignableFrom(typeof(T))
{
var obj = new Foo1();
//...
}
}
And I got the error "There is no implicit reference conversion from T to Interface1/2".
The problem is similar to Similiar to How to conditionally invoke a generic method with constraints?, but I can find a place to add (dynamic).
You can create an instance of a generic class using reflection.
public static void Create<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
var d1 = typeof(Foo1<>);
Type[] typeArgs = { typeof(T) };
var makeme = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(makeme);
}
else if (typeof(Interface2).IsAssignableFrom(typeof(T))
{
// same for Foo2
}
}
Lets assume I have these classes
Animal
Cat : Animal
Dog : Animal
If in a method somewhere I had the following:
Type animalType = someClass.Animal.GetType();
How can I cast someClass.Animal into whatever type is contained within animalType? Something like:
var animal = (animalType.Type)someClass.Animal;
You need a generic method for this:
public static class Converter
{
public static T ConvertTo<T>(this object source) where T :class
{
if (source is T)
{
return (T) source;
}
else
{
return null; // or throw exception
}
}
}
Then you can use Reflection to call this method:
class Animal { }
class Cat : Animal { }
class Dog : Animal
{
public override string ToString()
{
return "I'm a dog!";
}
public bool IsDog { get { return true; } }
}
Animal a = new Dog();
var methodInfo = typeof (Converter)
.GetMethod("ConvertTo", BindingFlags.Static | BindingFlags.Public);
var method = methodInfo.MakeGenericMethod(a.GetType());
var dog = method.Invoke(null, new object[] { a });
Console.WriteLine(dog.ToString());
In this case, it will write I'm a dog to console. but since the Invoke method returns an object you can't access the methods or properties of the Dog.In order to do that, you can use dynamic feature:
dynamic dog = method.Invoke(null, new object[] { a });
Console.WriteLine(dog.IsDog); // true
But then you lose the type-safety.
As a result, if you don't know the type that you want to cast at compile-time there is no way to do this directly using a type instance.
I'm trying to write a NullObject creation method, where I pass in a class name that implements an ICreateEmptyInstance interface (that is empty) and it walks it's properties looking for other classes that implement ICreateEmptyInstance and will create "Null" instances of those.
public interface ICreateEmptyInstance { }
public static class NullObject
{
public static T Create<T>() where T : ICreateEmptyInstance, new()
{
var instance = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties.Where(property => typeof(ICreateEmptyInstance).IsAssignableFrom(property.PropertyType)))
{
var propertyInstance = NullObject.Create<property.PropertyType>();
property.SetValue(instance, propertyInstance);
}
return instance;
}
}
I should be able to call it with this
var myEmptyClass = NullObject.Create<MyClass>();
Where I'm having issues is inside of the foreach loop, with this line
var propertyInstance = NullObject.Create<property.PropertyType>();
...obviously that doesn't work, but how can I accomplish creating a "null object" to assign to the instance I'm currently creating.
EDIT:
And what about generics?? I'd like empty instances created
foreach (var property in properties.Where(property => property.GetType().IsGenericType))
{
var propertyInstance = Enumerable.Empty<>(); //TODO: how do I get the type for here?
property.SetValue(instance, propertyInstance);
}
You can create a non-generic method and use it:
public static T Create<T>() where T : ICreateEmptyInstance, new()
{
return (T) Create(typeof (T));
}
private static object Create(Type type)
{
var instance = Activator.CreateInstance(type);
var properties = type.GetProperties();
foreach (var property in properties.Where(property => typeof(ICreateEmptyInstance).IsAssignableFrom(property.PropertyType)))
{
var propertyInstance = NullObject.Create(property.PropertyType);
property.SetValue(instance, propertyInstance);
}
return instance;
}
I have a class (that I cannot modify) that simplifies to this:
public class Foo<T> {
public static string MyProperty {
get {return "Method: " + typeof( T ).ToString(); }
}
}
I would like to know how to call this method when I only have a System.Type
i.e.
Type myType = typeof( string );
string myProp = ???;
Console.WriteLinte( myMethodResult );
What I've Tried:
I know how to instantiate generics classes with reflection:
Type myGenericClass = typeof(Foo<>).MakeGenericType(
new Type[] { typeof(string) }
);
object o = Activator.CreateInstance( myGenericClass );
However, is this proper to instantiate a class since I am using the static property? How do I gain access to the method if I can't compile time cast it? (System.Object does not have a definition for static MyProperty)
Edit
I realized after posting, the class I'm working with is a property, not a method. I apologize for the confusion
The method is static, so you don't need an instance of an object. You could directly invoke it:
public class Foo<T>
{
public static string MyMethod()
{
return "Method: " + typeof(T).ToString();
}
}
class Program
{
static void Main()
{
Type myType = typeof(string);
var fooType = typeof(Foo<>).MakeGenericType(myType);
var myMethod = fooType.GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);
var result = (string)myMethod.Invoke(null, null);
Console.WriteLine(result);
}
}
Well, you don't need an instance to call a static method:
Type myGenericClass = typeof(Foo<>).MakeGenericType(
new Type[] { typeof(string) }
);
Is OK... then, simply:
var property = myGenericClass.GetProperty("MyProperty").GetGetMethod().Invoke(null, new object[0]);
should do it.
typeof(Foo<>)
.MakeGenericType(typeof(string))
.GetProperty("MyProperty")
.GetValue(null, null);
You need something like this:
typeof(Foo<string>)
.GetProperty("MyProperty")
.GetGetMethod()
.Invoke(null, new object[0]);
How can I set generic type dynamically?
public class A
{
public int X { get; set; }
public A()
{
X = 9000;
}
}
public class Class1
{
public void Test()
{
List<A> theList = new List<A>() {
new A { X = 1 },
new A { X = 2 }
};
object testObj = theList;
var argType = testObj.GetType().GetGenericArguments()[0];
Foo(testObj as ICollection<argType>); // ?
}
public void Foo<T>(ICollection<T> items) where T:new()
{
T newItem = new T();
items.Add(newItem);
}
To do in "regular" c# you would use reflection to obtain the MethodInfo, then use MakeGenericMethod() and Invoke(). However, this is easier:
Foo((dynamic)testObj);
The reflection approach here is:
var method = typeof(Class1).GetMethod("Foo").MakeGenericMethod(argType);
method.Invoke(this, new object[] { testObj });
You can't do that, because in the Foo function you are supposed to do something with the collection, and there's no guarantee that the type will be safe.
The only way is using an "object" then casting to the proper type within the Fooo function.