I have the following class:
Public Class WcfClient(Of T)
Private _Cliente As T
Public ReadOnly Property Client As T
Get
Return _Cliente
End Get
End Property
T, represents a Wcf Channel, that is created like this:
Dim channel As New ChannelFactory(Of T)(basicHttpBinding, remoteAddress)
'Set the property
_Cliente = channel.CreateChannel()
Now, with reflection, I am creating an Instance of WcfClient, and I want to execute a Method that is inside the Client Property.
Type tipo = FindInterface(Request.GetFriendlyUrlSegments()[0]);
Type genType = typeof (WcfClient<>).MakeGenericType(tipo);
var client = Activator.CreateInstance(genType);
var clientProp = client.GetType().
GetProperties().Where(p => p.Name == "Client").FirstOrDefault();
if (clientProp != null)
{
var method =clientProp.PropertyType
.GetMethod(Request.GetFriendlyUrlSegments()[1]);
ProcesoBase procesoBase = new ProcesoBase();
foreach (var prop in typeof (ProcesoBase).GetProperties())
{
//Here we have some code to fill ProcesoBase properties
}
}
var result = method.Invoke(clientProp, new object[] { procesoBase });
When calling method.Invoke I am getting Object does not match target type in exception
I am getting the MethodInfo class from the clientProp variable so I don't get it how this is happening.
Could this be because the generated Channel class is built as proxy_TransparentProxy class?
Ok, I solved it by getting the client Property using the GetValue instead of using the GetProperties:
PropertyInfo p = client.GetType().GetProperty("Client");
MethodInfo m = p.PropertyType.GetMethod(Request.GetFriendlyUrlSegments()[1]);
object clientProp = p.GetValue(client);
Related
I have a generic class and a property of type Action<,>. I am wondering if there is a way to actually invoke this delegate using reflection in runtime, not just set value to this class property (via PropertyInfo.SetValue).
I tried a lot of things, like using expressions, dummy casting, read forums, but none of the solutions worked for me.
Workaround:
What I could think of is creating a dummy method which internally calls the delegate, and with reflection is fairly easy to invoke this method.
public class Student
{
public string Name { get; set; }
}
public class ConfigData<T>
where T: class
{
public Action<T, object> ValueInjector { get; set; }
public void SetValue(T entity, object valueToSet)
{
this.ValueInjector(entity, valueToSet);
}
}
class Program
{
static void Main(string[] args)
{
var configObj = new ConfigData<Student>()
{
ValueInjector = (x, y) =>
{
// Some custom logic here
x.Name = y.ToString();
}
};
// Parameters
Student student = new Student();
object valueToSet = "Test";
Type configType = configObj.GetType();
PropertyInfo propertyInfo = configType.GetProperty("ValueInjector");
// Invoke the property info somehow with the parameters ?
// Workarround - invoke a dummy method instead
MethodInfo methodInfo = configType.GetMethod("SetValue");
methodInfo.Invoke(configObj, new object[] { student, valueToSet });
Console.WriteLine(student.Name);
}
}
I want to be able to invoke the propertyInfo variable and pass to it the two parameters I already have (student, valueToSet), since I know that it represent a delegate which can be run.
Update:
I tried with castings as suggested by #HimBromBeere.
//Error in runtime
var del = (Action)propertyInfo.GetValue(configObj, null);
//Error in runtime
var del = (Action<object, object>)propertyInfo.GetValue(configObj, null);
// Works but no generic
var del = (Action<Student, object>)propertyInfo.GetValue(configObj, null);
del.Invoke(student, valueToSet);
Only the last casting works and I am able to call Invoke on the delegate (no need of DynamicInvoke) and it works. However this is not a solution because I do not know the exact type to cast in runtime. I have it as variable T. Something like:
var del = (Action<T, object>)propertyInfo.GetValue(configObj, null);
So maybe if I manage to make a generic Type like this:
var d1 = typeof(Action<,>);
Type[] typeArgs = { propertyInfo.DeclaringType.GenericTypeArguments[0], typeof(object) };
Type delegateType = d1.MakeGenericType(typeArgs);
there might be a way to do this conversion and execute. Still wondering.
You can cast the value returned from the property back to a delegate, e.g:
var del = (Action)propertyInfo.GetValue(configObj, null);
Now call the delegate with your params:
del.DynamicInvoke(student, valueToset)
I have a static class which looks for an implementation of an abstract type and stores it as a static property
similar to the below:
public static class MyStaticClass
{
private static MyAbstractType _MyAbstractImplementation;
public static MyAbstractType MyAbstractImplementation
{
get => _MyAbstractImplementation ?? ( _MyAbstractImplementation = FindImplementation());
private set => _MyAbstractImplementation = value;
}
}
And I am trying to call a method of MyAbstractImplementation (which contains no static properties or methods) via reflection:
var myAssembly = Assembly.Load("MyStaticClassAssembly")
var myType = myAssembly.GetTypes().First(t => t.Name == "MyAbstractType");
var myImplementation = myType.GetProperties()
.First(p=>p.ReflectedType?.Name == "MyAbstractImplementation")
.GetValue(null);
var obj = myType.GetMethod("SomeMethod")?.Invoke(
null,
new object[]
{
// Some args
});
The above code causes the following exception on getting the value of MyAbstractImplementation:
System.Reflection.TargetException: Non-static method requires a target.
Evidently, this is because I am passing null to GetValue(), so I try passing myAssembly rather than null and I get the following exception:
System.Reflection.TargetException: Object does not match target type.
Out of desperation, I try passing myType and myImplementation but I still get the same exception.
What am I meant to be passing to GetValue()?
From the error you are getting MyAbstractImplementation is not a static property, so it needs an instance to be run on. You are basically trying to write the following code:
new MyAbstractType().MyAbstractImplementation.SomeMethod();
Both the property and method access need the target to run against (the left side of '.'). So you need an instance of myType. Also the method will need the instance, which is the result of getting the property (myImplementation).
var myAssembly = Assembly.Load("MyStaticClassAssembly");
var myType = myAssembly.GetTypes().First(t => t.Name == "MyAbstractType");
var myTypeInstance = Activator.CreateInstance(myType); // Asuming has a default constructor
var myImplementation = myType.GetProperties()
.First(p => p.ReflectedType?.Name == "MyAbstractImplementation")
.GetValue(myTypeInstance);
var obj = myType.GetMethod("SomeMethod")?.Invoke(
myImplementation,
new object[]
{
// Some args
});
From how you write the code myImplementation should also be of type myType (myType.GetMethod("SomeMethod")) if it isn't replace it with: myImplementation.GetType().GetMethod("SomeMethod").
I've writing a small method whose sole purpose is to check if a property is null for a given class. If the property is null, then create a new instance of it. I'm getting stuck on part where I'm actually setting a value:
public static void CheckIfPropertyIsNull<TEntity>(SomeBusinessEntity someBusinessEntity) where TEntity : new()
{
var properties = typeof(SomeBusinessEntity).GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
Type currentType = propertyInfo.PropertyType;
if (currentType == typeof(TEntity))
{
var propertyData = propertyInfo.GetValue(someBusinessEntity, null);
if (propertyData == null)
{
object instance = Activator.CreateInstance(typeof(TEntity));
// And then?
//propertyInfo.SetValue(null, instance);
return;
}
}
}
}
I try to use the SetValue() method but with no luck.
In your SetValue you still have to give the instance of the owner of the property: someBusinessEntity.
object instance = new TEntity();
// And then
propertyInfo.SetValue(someBusinessEntity, instance);
Note that your logic seems odd to me. You are using a generic type to set all properties. Why not use the type of the property?
I have a generic class that has a generic method that uses the same type as the type passed when instantiating the object. At runtime, I will only know the name of the object I need to pass in by a string representation of that object name. I've read a few things about using Activator and possibly using dynamic but I can't wrap my head around how I need to make this work. Here's a snippet of what my generic class looks like:
public class MyClass<T> where T : class, new()
{
public IList<T> MyMethod(Stream stream)
{
var data = new List<T>();
// stuff to create my list of objects
return data;
}
}
I need to return my IList from the MyMethod() method based on the name of the object I'm passing in as a string.
I could just do a switch/case on the string and then instantiate the MyClass within the case with the reference to the "real" object, but I'm wondering if there's a better (shorter and cleaner) way of doing this.
TIA
Your wrapper got the following signature:
public class MyClass<T> where T : class, new()
it basically says "T needs to be a class and have a default constructor". The interesting part is about the default constructor. It means that the class must have a constructor with no arguments.
It tells .NET that you can invoke:
var obj = new T();
So the first step is to do just that:
public class MyClass<T> where T : class, new()
{
public IList<T> MyMethod(Stream stream)
{
var data = new List<T>();
//this
var obj = new T();
return data;
}
}
next you wanted to invoke a method. That's done with the help of reflection.
A simple example is:
var obj = new T();
//get type information
var type = obj.GetType();
//find a public method named "DoStuff"
var method = type.GetMethod("DoStuff");
// It got one argument which is a string.
// .. so invoke instance **obj** with a string argument
method.Invoke(obj, new object[]{"a string argument"});
Update
I missed the important part:
I need to return my IList from the MyMethod() method based on the name of the object I'm passing in as a string.
If the type is declared in the same assembly as your executing code you can just pass the full type name like Some.Namespace.ClassName" toType.GetType()`:
var type = Type.GetType("Some.Namespace.ClassName");
var obj = Activator.CreateInstance(type);
If the class is declared in another assembly you need to specify it:
var type = Type.GetType("Some.Namespace.ClassName, SomeAsseblyName");
var obj = Activator.CreateInstance(type);
The rest is pretty much the same.
If you only have the class name you can traverse the assembly to find the correct type:
var type = Assembly.GetExecutingAssembly()
.GetTypes()
.FirstOrDefault(x => x.Name == "YourName");
var obj = Activator.CreateInstance(type);
It sounds like you want to create the generic type so that you can create an instance of it.
//Assuming "typeName" is a string defining the generic parameter for the
//type you want to create.
var genericTypeArgument = Type.GetType(typeName);
var genericType = typeof (MyGenericType<>).MakeGenericType(genericTypeArgument);
var instance = Activator.CreateInstance(genericType);
This assumes that you already know what the generic type is, but not the type argument for that generic type. In other words, you're trying to determine what the <T> is.
Use Reflection. Make MyMethod static. See the code below:
public object run(string typename, Stream stream)
{
var ttype = Assembly
.GetExecutingAssembly()
.GetTypes()
.FirstOrDefault(x => x.Name == typename);
MethodInfo minfo = typeof(MyClass)
.GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);
return minfo
.MakeGenericMethod(ttype)
.Invoke(null, new object[] { stream });
}
With this code:
World w = new World();
var data = GetData<World>(w);
If I get w with reflection and this can be of type World, Ambient, Domention, etc.
How can I get GetData ???
I only have the instance object:
var data = GetData<???>(w);
var type = <The type where GetData method is defined>;
var genericType = typeof(w);
var methodInfo = type.GetMethod("GetData");
var genericMethodInfo = methodInfo.MakeGenericMethod(genericType);
//instance or null : if the class where GetData is defined is static, you can put null : else you need an instance of this class.
var data = genericMethodInfo.Invoke(<instance or null>, new[]{w});
You do not need to write section. C# implicity decides the type of the parameter in a generic method if type is not declared; just go with:
var data = GetData(w);
Here is a sample;
public interface IM
{
}
public class M : IM
{
}
public class N : IM
{
}
public class SomeGenericClass
{
public T GetData<T>(T instance) where T : IM
{
return instance;
}
}
And you may call it like;
IM a = new M();
SomeGenericClass s = new SomeGenericClass();
s.GetData(a);