I want to do the following:
private static Dictionary<string, Delegate> handlers = new Dictionary<string, Delegate>();
private static void RecievedMessage(object sender, RecievedMessageEventArgs e) {
if(e == null || e.Message == null) return;
if(e.Message is RegisterMethodMessage) {
var registerMethodMsg = (RegisterMethodMessage)e.Message;
if(handlers.ContainsKey(registerMethodMsg.MethodName)) {
handlers[registerMethodMsg.MethodName] += registerMethodMsg.Handler; //Error
} else {
handlers.Add(registerMethodMsg.MethodName, registerMethodMsg.Handler);
}
}
}
A delegate added to the chain with the same key in the dictionary will have the same method signature.
If I were to substitute "Delegate" with a specific one like Action, the above code would work.
So my question is:
Is it possible to do the same without the substitution and without a lot of "hacking"?
Is there any reason you can't do this:
handlers[registerMethodMsg.MethodName] =
Delegate.Combine(
handlers[registerMethodMsg.MethodName],
registerMethodMsg.Handler);
Related
I have the following scenario
I have a loop which has an Update callback which several objects use CreateDelegate to creat their own delegates and add themselves to it at runtime.
now I want to avoid creating N delegates for N objects so I thought using a multi cast open delegate I can create one delegate
add all instances to it and call it,
How can I do it via reflection
I create the delegate using CreateDelegate from my method info once and then call NewMultiCastDelegate via reflection and send it the list of objects but things go wron when I call invoke with another dummy instance to call it, unprotected memory violation exception is thrown.
How can I do it?
I can not do it without reflection since my objects methods will be known at runtime and anyone with an Update method should be called by this loop manager.
This is for a game engine
UPDATE:
There are two issues with using MulticastDelegate + open instance delegates.
It's not possible to invoke open instance delegates with multiple unrelated types. Take types A and B, each with an Update method. An open instance delegate of A.Update can be invoked with instances of A (or types derived from A), but not with instances of B. That's because A.Update and B.Update are unrelated as far as the .NET runtime is concerned.
Multiple open instance delegates can be combined in a single MulticastDelegate, but this doesn't fit your use case. You want to call the Update method on each instance in a list. Invoking a MulticastDelegate will sequentially call each delegate in its invocation list with the same parameter list. So a MulticastDelegate with multiple open instance delegates could be used to invoke a list of methods on a single instance, but not a single method on a list of instances. Does that make sense?
I assume you're trying to speed up adding a Unity Component to your engine emulator, and that's why you want to stop calling CreateDelegate for each one.
Instead of using a MulticastDelegate, you can achieve a speedup by creating open instance delegates the first time a type is added, then caching those delegates for reuse.
Here's some code along those lines:
public class ComponentEventAggregator
{
public void AddComponent(object component)
{
var typeGroup = this.GetTypeGroup(component.GetType());
typeGroup.AddComponent(component);
}
public void Update()
{
foreach (var typeGroup in this.typeGroupsByType.Values)
{
typeGroup.Update();
}
}
public void RemoveComponent(object component)
{
TypeGroup typeGroup;
if (this.typeGroupsByType.TryGetValue(component.GetType(), out typeGroup))
{
typeGroup.RemoveComponent(component);
}
}
private TypeGroup GetTypeGroup(Type type)
{
TypeGroup typeGroup;
if (!this.typeGroupsByType.TryGetValue(type, out typeGroup))
{
typeGroup = TypeGroup.Create(type);
this.typeGroupsByType[type] = typeGroup;
}
return typeGroup;
}
private abstract class TypeGroup
{
public abstract void Update();
// ... LateUpdate, OnApplicationPause, etc.
public abstract void AddComponent(object component);
public abstract void RemoveComponent(object component);
// Create a TypeGroup<T> for the specified type
public static TypeGroup Create(Type type)
{
var closedDelegatesType = typeof(TypeGroup<>).MakeGenericType(new[] { type });
var typeDelegates = closedDelegatesType.GetConstructor(Type.EmptyTypes).Invoke(new object[0]);
return (TypeGroup)typeDelegates;
}
}
private class TypeGroup<T> : TypeGroup where T : class
{
public TypeGroup()
{
this.update = CreateOpenDelegate("Update");
this.lateUpdate = CreateOpenDelegate("LateUpdate");
this.onApplicationPause = CreateOpenDelegate<bool>("OnApplicationPause");
// ...other Unity events
}
public override void Update()
{
if (this.update != null)
{
foreach (var component in this.components)
{
this.update(component);
}
}
}
public override void AddComponent(object component)
{
var t = component as T;
if (t != null)
{
this.components.Add(t);
}
}
public override void RemoveComponent(object component)
{
var t = component as T;
if (t != null)
{
this.components.Remove(t);
}
}
private static Action<T> CreateOpenDelegate(string functionName)
{
var method = GetMethod(functionName, Type.EmptyTypes);
if (method == null)
{
return null;
}
return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), method);
}
private static Action<T, TArg1> CreateOpenDelegate<TArg1>(string functionName)
{
var method = GetMethod(functionName, new[] { typeof(TArg1) });
if (method == null)
{
return null;
}
return (Action<T, TArg1>)Delegate.CreateDelegate(typeof(Action<T, TArg1>), method);
}
private static MethodInfo GetMethod(string functionName, Type[] parameterTypes)
{
return typeT.GetMethod(functionName, BindingFlags.Instance | BindingFlags.Public, null, parameterTypes, null);
}
private readonly Action<T> update;
private readonly Action<T> lateUpdate;
private readonly Action<T, bool> onApplicationPause;
private List<T> components = new List<T>();
private static readonly Type typeT = typeof(T);
}
private Dictionary<Type, TypeGroup> typeGroupsByType = new Dictionary<Type, TypeGroup>();
}
This gives a 50X speedup to add a Component compared to Delegate.CreateDelegate on my PC.
Test times with 1 million A and 1 million B instances:
10892ms add closed delegates with CreateDelegate for all Components
11ms Update via the closed delegates
187ms add all Components to the type-based aggregator
30ms Update via the open instance delegates (i.e. Update on aggregator)
The Update method in both A and B increments a private static int.
ORIGINAL:
It sounds like you would be better off exposing a C# event on your loop manager and adding subscriptions that call the Update methods. Alternately all the types with the Update method could implement an IUpdater interface, then you'd send a list of IUpdater instances to the loop manager instead of a list of objects.
Assuming you really do have some other good reason for using reflection...
class Program
{
public class Updater
{
public void AddUpdateListeners(object[] listeners)
{
Func<object, MethodInfo> getUpdateMethod = l =>
l.GetType()
.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null);
listeners
.Select(listener => new { listener, update = getUpdateMethod(listener) })
.Where(l => l.update != null)
.Select(l => Delegate.CreateDelegate(typeof(UpdateDelegate), l.listener, l.update))
.OfType<UpdateDelegate>()
.ToList()
.ForEach(d => this.updateDel += d);
}
public void PublishCallbacks()
{
var handler = this.updateDel;
if (handler != null)
{
handler();
}
}
private delegate void UpdateDelegate();
private UpdateDelegate updateDel;
}
static void Main(string[] args)
{
var updater = new Updater();
updater.AddUpdateListeners(new object[] { new A(), new B(), });
updater.PublishCallbacks();
}
public class A
{
public void Update()
{
Console.WriteLine("A updated");
}
}
public class B
{
public void Update()
{
Console.WriteLine("B updated");
}
}
}
I have a collection of strings. For example,
string[] coll={"1", "2", "3" ..."100"..."150"...}
and I have respective methods for the string collection such as
void Method1, void Method2, void Method100
I select appropriate method like that:
string selector=string.Empty;
switch(selector)
{ case "1":
MethodOne();
break;
........
case "150":
Method150();
break;
}
The above code is really bored and I will have more string elements in the string collection {"150" ... "250"...}.
How to make like that:
string sel=col[55];
if(sel!=null)
// call here the respective method(method55)
I do not want to use switch operator cause it gives rise to surplus of code.
Solution 1:
Use a delegate mapping. This is the faster solution.
private static Dictionary<string, Action> mapping =
new Dictionary<string, Action>
{
{ "1", MethodOne },
// ...
{ "150", Method150 }
};
public void Invoker(string selector)
{
Action method;
if (mapping.TryGetValue(selector, out method)
{
method.Invoke();
return;
}
// TODO: method not found
}
Solution 2:
Use reflection. This is slower and is appropriate only if your methods have strict naming (eg. 1=MethodOne 150=Method150 will not work).
public void Invoker(string selector)
{
MethodInfo method = this.GetType().GetMethod("Method" + selector);
if (method != null)
{
method.Invoke(this, null);
return;
}
// TODO: method not found
}
You can declare a dictionary with your keys and actions like
Dictionary<string, Action> actions = new Dictionary<string, Action>()
{
{ "1", MethodOne },
{ "2", ()=>Console.WriteLine("test") },
............
};
and invoke it as
actions["1"]();
PS: Presuming method void MethodOne(){ } is declared somewhere.
You can use dynamic invocation
var methodName = "Method" + selector;
var method = this.GetType().GetMethod(methodName);
if (method == null)
{
// show error
}
else
method.Invoke(this, null);
Public void test(){
Console.WriteLine("Hello World");
}
Is it possible to save this method in a Dictionary, and call this method if Dicitionary contains the method's key value.
For example like this:
Hashtable table = new Hashtable<method, string>();
string input = "hello"
foreach(Dictionary.entry t in table){
if(input == t.Key){
//Call the t.value method.
}
}
class Program
{
private static void Main(string[] args)
{
var methods = new Dictionary<string, Action>();
//choose your poison:
methods["M1"] = MethodOne; //method reference
methods["M2"] = () => Console.WriteLine("Two"); //lambda expression
methods["M3"] = delegate { Console.WriteLine("Three"); }; //anonymous method
//call `em
foreach (var method in methods)
{
method.Value();
}
//or like tis
methods["M1"]();
}
static void MethodOne()
{
Console.WriteLine("One");
}
}
Yes, that's pretty easy: just use the Action delegate class:
Encapsulates a method that has no parameters and does not return a value.
var dict = new Dictionary<string, Action>();
dict.Add("hello", test);
var input = "hello";
dict[input]();
Demo
You can use Func to reference your methods and then call them in the loop
https://msdn.microsoft.com/en-us/library/bb549151%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
And as #Lucas Trzesniewski answered your can use Action if your methods has no params
I have a generic method
public delegate void Handler<T>(T val);
I enable users to register to events and provide this delegate.
I need to save the list of delegate according to their types.
I tried saving in a dictionary of Type and object. when adding the method I cast it to a
List<Handler<T>>
according to the T. but then when an event occurred I do not have the T so cannot cast to the relevant list of generic handlers (I do have the Type but not the T)
I solved this by saving methodInfo list for each type
private Dictionary<Type, List<MethodInfo>> handlers = new Dictionary<Type, List<MethodInfo>>();
public delegate void Handler<T>(T val);
public void Register<T>( Handler<T> handler )
{
List<MethodInfo> lst;
if (!handlers.TryGetValue(typeof(T), out lst))
{
lst = new List<MethodInfo>();
handlers.Add(typeof(T), lst);
}
lst.Add(handler.Method);
}
public void RaiseEvent( string value)
{
foreach (KeyValuePair<Type, List<MethodInfo>> pair in handlers)
{
object typedValue;
if (pair.Key.IsEnum)
{
typedValue = Enum.Parse(pair.Key, value);
}
else
{
typedValue = Convert.ChangeType(value, pair.Key);
}
foreach (MethodInfo methodInfo in pair.Value )
{
methodInfo.Invoke(null, new[] { typedValue });
}
}
}
}
but the problem is that this approach will work only if the method is static , otherwise it will require the type of class.
is there any solution for this problem???
enable generic events...
thanks!
Maybe this will help:
public delegate void Handler<in T>(T val);
private List<Delegate> m_list = new List<Delegate>();
public void AddListener<T>(Handler<T> handler) {
m_list.Add(handler);
}
public void Call(object eventArg) {
foreach (var handler in m_list) {
handler.DynamicInvoke(eventArg);
}
}
Then, if you have a handler like this:
private void MyHandler(int val) {
// Do something
}
You can add it to the list like this:
AddListener<int>(MyHandler);
(This assumes I correctly understood what you're trying to do. I'm not sure though.)
You could also make a handler repository using a non-generic delegate, something like:
public delegate void Handler(object val);
public delegate void Handler<T>(T val);
public class HandlerRepository
{
private Dictionary<Type, Handler> handlers = new Dictionary<Type, Handler>();
public void RegisterHandler<T>(Handler<T> handler)
{
//error checking omitted
//create a non-generic handler that calls the generic handler
//with the correct type.
handlers.Add(typeof(T), (value)=>handler((T)value));
}
public void ExecuteHandler<T>(T value)
{
//error checking ommited
handlers[typeof(T)](value);
}
}
and use it like this:
Handler<int> handleInt = value => Console.WriteLine("Int32 is {0}", value);
Handler<string> handleString = value => Console.WriteLine("String is {0}", value);
HandlerRepository repo = new HandlerRepository();
repo.RegisterHandler(handleInt);
repo.RegisterHandler(handleString);
//this call boxes the argument to an object
repo.ExecuteHandler(5); // "Int32 is 5"
repo.ExecuteHandler("Hello, world"); "String is Hello, world"
Have tried to solve this for quite a while now, but without luck... My idea was to have some sort of a configuration for different settings, for instance.. controlling how exceptions are handled.
Some of my code :)
public class ErrorEventArgs : EventArgs
{
public bool Handled { get; set; }
...
...
}
A property in my main class like :
EventHandler<ErrorEventArgs> ErrorConfiguration {get; set;}
I then have an OnError where I need to know value of Handled,
internal void OnError(ErrorEventArgs args)
{
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => ??? // invoke ErrorConfiguration?
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}
How can this be solved?
I can do like this, if it's the EventHandler without the Func, but I want to encapsulate the boolean expression. Why cant I chain the lambda... :(
EventHandler<ErrorEventArgs> IsHandled;
IsHandled = (sender, e) => e.ErrorContext.Handled;
I am not completely sure what you want to achieve, exactly. But you can do something like:
IsHandled = ev => { ev(this, args); return args.Handled; };
Even though I am not sure this is more readable, faster, cleaner, or anything like that. I would just go with something like
if (ErrorConfiguration != null) ErrorConfiguration(this, args);
if (!args.Handled) error(this, args);
You really don't need any lambda to call your just need to call your delegate directly:
internal void OnError(ErrorEventArgs args)
{
if (ErrorConfiguration != null)
ErrorConfiguration(this, args);
if (args.Handled)
error(this, args);
}
If you want to the use the same thing in a lambda, you'll have do to this, which will take more lines of code:
internal void OnError(ErrorEventArgs args) {
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => {
ErrorConfiguration(this, ev);
return ev.Handled;
};
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}