i would like to create a generic delegate but i only know the type while the execution.
here is the delegate that i want to create :
public delegate void MyDel<T>(T t,string msg);
and here is the method in which i want to instantiate and use the delegate
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");
Delegate test = Delegate.CreateDelegate(typeof(MyDel<typeSet>, method);
where typeSet is unknow for me at the compilation.
and unfortunately, the method that i want to call is not static.
Does anyone have any idea ?
Thanks in advance
You need to create the specific delegate type using MakeGenericType:
Type template = typeof(MyDel<>);
Type specific = template.MakeGenericType(typeSet);
Delegate test = Delegate.CreateDelegate(specific, method);
I think that's what you're after...
Related
I have a project which reads an external DLL through reflection and
System.Reflection.Assembly BuildDll = System.Reflection.Assembly.LoadFrom(System.AppDomain.CurrentDomain.BaseDirectory + BuildDllName);
Type BuildWindow = BuildDll.GetType(BuildFormType);
System.Reflection.MethodInfo constructors = BuildWindow.GetMethod("Initialize");
lMethod = BuildWindow.GetMethod("Submit");
TypeUserControl = Activator.CreateInstance(BuildWindow);
In this code I load the DLL and read its two methods Submit(to call this method to perform some actions) & Initialize(to pass the data required by DLL)
Now I have to return a function's result from my code to the DLL on a button event of that external DLL, there is a method in my code which returns the desired integer value
int GetValue(string id, int key)
In the external DLL a delegate is been defined as
private System.Delegate _BaseFunction;
public Delegate BaseFunction
{
set { _BaseFunction= value; }
}
On button Click event of external DLL result needed to be displayed
private void btnBaseInvoke_Click(object sender, RoutedEventArgs e)
{
object[] parameters = new object[2];
parameters[0]= Convert.ToString(txtParam30.Text.Trim());
parameters[1]= Convert.ToInt32(txtParam31.Text.Trim());
object obj = _BaseFunction.DynamicInvoke(parameters);
MessageBox.Show(Convert.ToString(obj));
}
What I am not getting is how will I initialize this delegate in my code & pass these parameters to my function?
The external DLL is a bit annoying in using a System.Delegate instead of a more specific delegate, but this is still very easy to solve.
To turn your GetValue method into a delegate, you can just do something like this:
var delegate = (Func<string, int, int>)GetValue;
That's it :)
Since you're using reflection (Do you have to? Isn't there an interface you could use instead or something? Do you have to load the assembly dynamically in the first place?), you may need to manually convert the resulting delegate to Delegate (which is just another cast), but I'm not sure if even that is necessary. Just call the setter on the property and pass it the delegate and you should be fine.
Did you try MethodBase.Invoke Method (Object, Object[])?
Maybe this will help you?
The code snippet below is from an ASP.NET MVC application. It accepts all parameters from browser. I believe it's vulnerable.
I'm testing an application's security, it uses Invoke method, but accepts the Object type, method and parameters dynamically from user's input. I believe it is dangerous and I'm trying to prove it.
Do you think I can invoke Console.Write or execute some sort of arbitrary/dangerous code?
I want to try to use C# Invoke Method to write to console to prove the vulnerability. This is what I did:
static void Main(string[] args)
{
Type magicType = Type.GetType("System");
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
object magicClassObject = magicConstructor.Invoke(new object[] { });
MethodInfo magicMethod = magicType.GetMethod("Console.Write");
object magicValue = magicMethod.Invoke(magicClassObject, new object[] { 100 });
}
But it doesn't work. It says Object is not initialized. What am I missing?
System is not a type, it's a namespace. You're actually looking for System.Console, which is the console class. After that, you're looking for the WriteLine method with the proper overload, which takes an int, which is what you pass to Type.GetMethod. Only then, you can invoke the MethodInfo object using Invoke passing null as the object (as this is a static class) and the right parameter.
What you actually want is this:
Type magicType = Type.GetType("System.Console");
var method = magicType.GetMethod("WriteLine", new[] { typeof(int) });
method.Invoke(null, new object[] { 100 });
I have a string whose content is name of 1 function in my WP apps. For example, assume that I have:
string functionName = "button3_Click"
So I would like to call the button3_Click() in my apps. I tried the GetRuntimeMethod method in System.Reflection but the result returned is null, so when I use invoke I got the System.NullReferenceException. My code to call this function is:
System.Type[] types = { typeof(MainPage), typeof(RoutedEventArgs) };
string functionName = "button3_Click";
System.Type thisType = this.GetType();
MethodInfo method = thisType.GetRuntimeMethod(functionName, types);
object[] parameters = {this, null};
method.Invoke(this, parameters);
And the prototype of button3_Click is:
private void button3_Click(object sender, RoutedEventArgs e)
So how can I call the function whose name contained in the string? Thank you so much for you help.
Update
I can call the button3_Click() method by changing access level of this method to public, is there any way to keep access level of this method is private and I can call this method? Thank you for your help.
Finally
I think I should use the code like this, it can get all method even its access level is private or public:
System.Type[] types = { typeof(MainPage), typeof(RoutedEventArgs) };
string functionName = "button6_Click";
TypeInfo typeinfo = typeof(MainPage).GetTypeInfo();
MethodInfo methodinfo = typeinfo.GetDeclaredMethod(functionName);
object[] parameters = {this, null};
methodinfo.Invoke(this, parameters);
Thank you for your help.
If your app is a Windows Runtime app, use GetTypeInfo extension method on thisType and then use TypeInfo.GetDeclaredMethod method:
using System.Reflection;
...
System.Type thisType = this.GetType();
TypeInfo thisTypeInfo = thisType.GetTypeInfo();
MethodInfo method = thisTypeInfo.GetDeclaredMethod(functionName);
object[] parameters = {this, null};
method.Invoke(this, parameters);
It is said in documentation that GetDeclaredMethod returns all public members of a type, but according to .NET Reference Source, the documentation seems to be incorrect: it calls Type.GetMethod with flags constant that contains BindingFlags.NonPublic.
There are restrictions on Silverlight reflection:
In Silverlight, you cannot use reflection to access private types and members. If the access level of a type or member would prevent you from accessing it in statically compiled code, you cannot access it dynamically by using reflection. (source)
Look into LambdaExpressions as it might be a workaround in this case.
Given below are two methods which create a delegate to set a field in a class. One method uses generics and the other does not.
Both the methods return a delegate and they work fine. But if I try to use the delegate that has been created inside the CreateDelegate method, then the non-generic delegate 'del' works fine. I can place a breakpoint on the return statement and invoke the delegate by writting del(222). But If I try to invoke the generic delegate 'genericDel' by writting genericDel(434), it throws an exception:
Delegate 'System.Action' has some invalid arguments
Can anyone explain this quirk.
class test
{
public double fld = 0;
}
public static void Main(string[] args)
{
test tst = new test() { fld = 11 };
Type myType = typeof(test);
// Get the type and fields of FieldInfoClass.
FieldInfo[] myFieldInfo = myType.GetFields(BindingFlags.Instance | BindingFlags.Public);
var a = CreateDelegate<double>(myFieldInfo[0], tst);
var b = CreateDelegate(myFieldInfo[0], tst);
Console.WriteLine(tst.fld);
b(5.0);
Console.WriteLine(tst.fld);
a(6.0);
Console.WriteLine(tst.fld);
}
public static Action<T> CreateDelegate<T>(FieldInfo fieldInfo, object instance)
{
ParameterExpression numParam = Expression.Parameter(typeof(T), "num");
Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
BinaryExpression assExp = Expression.Assign(a, numParam);
Expression<Action<T>> expTree =
Expression.Lambda<Action<T>>(assExp,
new ParameterExpression[] { numParam });
Action<T> genericDel = expTree.Compile();
//try to invoke the delegate from immediate window by placing a breakpoint on the return below: genericDel(323)
return genericDel;
}
public static Action<double> CreateDelegate(FieldInfo fieldInfo, object instance)
{
ParameterExpression numParam = Expression.Parameter(typeof(double), "num");
Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
BinaryExpression assExp = Expression.Assign(a, numParam);
Expression<Action<double>> expTree =
Expression.Lambda<Action<double>>(assExp,
new ParameterExpression[] { numParam });
Action<double> del = expTree.Compile();
//try to invoke the delegate from immediate window by placing a breakpoint on the return below: del(977)
return del;
}
I think I understood the issue; you are having problems invoking a generic delegate from the immediate window when the compile-time type of the delegate is an open generic type.
Here's a simpler repro:
static void Main() { Test<double>(); }
static void Test<T>()
{
Action<T> genericDel = delegate { };
// Place break-point here.
}
Now, if I try executing this delegate from within the Test method (by placing a break-point and using the immediate window) like this:
genericDel(42D);
I get the following error:
Delegate 'System.Action<T>' has some invalid arguments
Note that this not an exception like you have stated, but rather the 'immediate window version' of compile-time error CS1594.
Note that such a call would have failed equally at compile-time because there is no implicit or explicit conversion from double to T.
This is debatably a shortcoming of the immediate window (it doesn't appear to be willing to use additional 'run-time knowledge' to help you out in this case), but one could argue that it is reasonable behaviour since an equivalent call made at compile-time (in source code) would also have been illegal. This does appear to be a corner case though; the immediate window is perfectly capable of assigning generic variables and executing other code that would have been illegal at compile-time. Perhaps Roslyn will make things much more consistent.
If you wish, you can work around this like so:
genericDel.DynamicInvoke(42D);
(or)
((Action<double>)(object)genericDel)(42D);
The problem is that you are trying to invoke the delegate within the scope of the method that is creating it, before 'T' is known. It is trying to convert a value type (an integer) to the generic type 'T', which is not allowed by the compiler. If you think about it, it makes sense. You should only be able to pass in T as long as you are within the scope of the method that is creating the delegate, otherwise it wouldn't really be generic at all.
You need to wait for the method to return, then use the delegate. You should have no problem invoking the delegate after its completed:
var a = CreateDelegate<double>(myFieldInfo[0], tst);
var b = CreateDelegate(myFieldInfo[0], tst);
a(434);
I have several message queues that have specific messages on them.
I've created classes for these messages using xsd.exe.
I can receive a message syncronously and deseriazlise it with this method:
public oneOfMyTypes DeserializeMessage(XDocument message)
{
var serializer = new XmlSerializer(typeof(oneOfMyTypes));
var entity = (oneOfMyTypes)serializer.Deserialize(message.CreateReader());
return entity;
}
I then persist the entity via Fluent NHibernate.
So I've got about five message queues that all have their own type of message.
I would like to keep this little processor app maintainable, so that adding more message queues and message types doesn't become a pain.
So I have a list of queue names in my app.config that I use to create the message queues on start up and then I want to wire up a single method to the .ReceiveCompleted event of all queues:
void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
var queue = (MessageQueue)sender;
var message = queue.EndReceive(e.AsyncResult);
var body = message.Body.ToString();
var xml = XDocument.Parse(body);
var queueName = queue.QueueName;
Type entityType = GetTypeFromQueueName(queueName);
entityType entity = DeserializeMessage<entityType>(xml);
var repository = new LogRepository();
repository.AddEntity<entityType>(entity);
}
private T DeserializeMessage<T>(XDocument message)
{
var serializer = new XmlSerializer(typeof(T));
var entity = (T)serializer.Deserialize(message.CreateReader());
return entity;
}
public Type GetTypeFromQueueName(string queueName)
{
switch (queueName)
{
case "some-message-queue-name":
return typeof (oneOfMyTypes);
}
}
But when I try to pass entityType to the generic methods I get "Type or namespace name expected".
I'm probably doing something really silly, but I can't figure out how this should work.
I've tried using the dynamic keyword and also .MakeGenericType but no luck.
I've also looked at:
Dynamic Generic declaration of type T
Function returning a generic type whose value is known only at runtime
Determining a Generic Type at Runtime in Non-Generic Class
How to pass variable of type "Type" to generic parameter
But I'm still not getting it ... help?
Unfortunately, generics are not meant to function dynamically like this. Generic parameters must be defined at design time. It's been a while since I've used NHibernate, but isn't there a way to insert entities with a syntax like:
repository.AddEntity(entity, typeof(myEntityType));
EDIT:
or
Session.SaveOrUpdate(object);
This link should help you
http://todotnet.com/post/2006/11/13/Instantiating-Generic-Types-at-runtime.aspx
You should be able to go from the link i posted to call the methode through reflection.
See the following link:
http://www.victorchen.info/call-static-method-with-a-string-name/
So basically when you've created your generic Type, you then grab the MethodInfo of your static method and then call the Invoke method on the MethodInfo object.
(i haven't actually tried this but in theory i believe it should work)