I need some store where I can register some callback for automatically update.
class Store
{
readonly Dictionary<Type, Action<dynamic>> _callbacks = new Dictionary<Type, Action<dynamic>>();
public void Register<T>(Action<T> updateCallback)
{
_callbacks.Add(typeof(T), value => updateCallback(value));
}
public void Save<T>(T value)
{
_callbacks[typeof(T)](value);
}
}
class Program
{
private static string _stringField = "0";
private static int _intField = 0;
static void Main(string[] args)
{
var store = new Store();
store.Register<string>(value => _stringField = value);
store.Register<int>(value => _intField = value);
Console.WriteLine($"{_stringField}/{_intField}");
store.Save("5");
Console.WriteLine($"{_stringField}/{_intField}");
store.Save(7);
Console.WriteLine($"{_stringField}/{_intField}");
}
}
Output:
0/0 5/0 5/7
It works fine. I just don't like Action<dynamic> in Dictionary. Firstly it looks as a hack. Secondary it produces box operation in Save method, because of dynamic. I understand that I can't use only generics because I'm not in static context but I'm looking for a best solution for this sample. Please advise some code without changing of Program class. So I need to register something one time and it will be updated automatically each time of Save method call.
If you don't like dynamic, you can store your callbacks as Action<object>, like this:
class Store {
readonly Dictionary<Type, Action<object>> _callbacks = new Dictionary<Type, Action<object>>();
public void Register<T>(Action<T> updateCallback) {
// cast here
_callbacks.Add(typeof(T), value => updateCallback((T) value));
}
public void Save<T>(T value) {
_callbacks[typeof(T)](value);
}
}
Use Delegate, so Dictionary<Type, Delegate> is good enough
Delegate d = _callbacks[typeof(T)];
Action<T> action = (Action < T >)d;
Storing
delegates in collections is normal practice (not a hack)
Boxing to object is imperfect practice
Related
Is it possible to use the C#7 feature of out variables when the out variables is a Tuple?
The exact scenario I have is this:
private readonly Dictionary<int, (bool, DateTime)> _dictionary;
public void SomeMethod(int number)
{
if (this._dictionary.TryGetValue(number, out (bool isTrue, DateTime timestamp)) // what is the correct syntax?
// use isTrue and timestamp here
}
If this is possible, I can't seem to find the correct syntax.
Clarification: I would like to be able to deconstruct directly into isTrue and timestamp rather than having to create another variable.
Consider the following code:
using System;
using System.Collections.Generic;
namespace ConsoleApp1 {
class Program {
private static Dictionary<int, (bool, DateTime)> _dictionary;
public static void SomeMethod(int number) {
if (_dictionary.TryGetValue(number, out (bool isTrue, DateTime timestamp) booltime)) {
Console.WriteLine($"Found it: {booltime.isTrue}, {booltime.timestamp}");
}
else {
Console.WriteLine($"{number} Not Found");
}
}
static void Main(string[] args) {
_dictionary = new Dictionary<int, (bool, DateTime)>();
_dictionary.Add(0, (true, DateTime.Now));
SomeMethod(1);
SomeMethod(0);
}
}
}
It will produce the following output:
1 Not Found
Found it: True, 6/26/2018 4:56:59 PM
You can get a tuple back as an out parameter by either defining the variable within the call parameters or by defining a separate variable of the needed type. You can also use the var keyword like so:
if (_dictionary.TryGetValue(number, out var booltime)) {
Console.WriteLine($"Found it: {booltime.Item1}, {booltime.Item2}");
}
Note, that if you do this you will not have the named tuple properties, and you will have to use Item1 and Item2.
Yes you can! But you're also trying to deconstruct the tuple, which cannot be done there.
Try something like this:
public void SomeMethod(int number)
{
if (this._dictionary.TryGetValue(number, out var item))
{
var (isTrue, timestamp) = item;
}
}
You might want to (or should) name the values of the tuple:
private readonly Dictionary<int, (bool isTrue, DateTime timestamp)> _dictionary;
Then you can use the value names:
public void SomeMethod(int number)
{
if (this._dictionary.TryGetValue(number, out var item))
{
// use item.isTrue;
// use item.timestamp;
}
}
The objective here is to allow API consumers to register their model and how to extract data from that model. Using the ValueMapper below we provide a CreateMap method that registers the map name and function to call to retrieve the data as an object.
The idea here being that certain model have a little more work to get the data out correctly. Once the model is registered using CreateMap we'll store that in an internal list/dictionary for future look ups. I've tried a few different angles to solve this problem and this is very close but still is lacking since the caller cannot provide actual expression logic then can only return a straight value.
I've stripped down the code to the bare bones and if there's a better way to solve my problem i'm open to suggestions.
// static class that I would like to hold a list of 'expressions' that can be looked up and executed multuples times by the run time logic
public static class ValueMapper
{
private static Dictionary<string, LambdaExpression> _rules = new Dictionary<string, LambdaExpression>();
public static void CreateMap<T>(string ruleName, Expression<Func<T, object>> valueExpression)
{
_rules.Add(ruleName, valueExpression);
}
}
public class Consumer
{
public Consumer()
{
// This works but doesn't allow for registering further logic
ValueMapper.CreateMap<ExternalUser>("foo", user => user.FirstName);
// This has a compiler error as follows : "A lambda expression with a statement body cannot be converted to an expression tree"
ValueMapper.CreateMap<ExternalUser>("foo", user =>
{
return user.FirstName + user.LastName;
});
}
}
// some external class
public class ExternalUser
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
}
From your description it seems you don't need expressions, simple delegates should do:
public static class ValueMapper {
private static Dictionary<string, Func<object, object>> _rules = new Dictionary<string, Func<object, object>>();
public static void CreateMap<T>(string ruleName, Func<T, object> valueFunc) {
_rules.Add(ruleName, c => valueFunc((T) c));
}
}
If there is only one mapping per target type - no need to use strings, use types:
public static class ValueMapper {
private static Dictionary<Type, Func<object, object>> _rules = new Dictionary<Type, Func<object, object>>();
public static void CreateMap<TFrom, TTo>(Func<TFrom, TTo> valueFunc) {
_rules.Add(typeof(TFrom), c => valueFunc((TFrom)c));
}
public static object Map<T>(T instance) {
if (_rules.ContainsKey(typeof(T)))
return _rules[typeof(T)](instance);
// or throw here, or return null, depending on what you need
return instance;
}
}
If you know types you are mapping to - use them:
public static class ValueMapper {
private static Dictionary<Type, Func<object, object>> _rules = new Dictionary<Type, Func<object, object>>();
public static void CreateMap<TFrom, TTo>(Func<TFrom, TTo> valueFunc) {
_rules.Add(typeof(TFrom), c => valueFunc((TFrom)c));
}
public static TTo Map<TTo>(object instance) {
if (_rules.ContainsKey(instance.GetType()))
return (TTo) _rules[instance.GetType()](instance);
// throw here if necessary
return default(TTo);
}
}
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");
}
}
}
im trying to write some kind a strongly typed routing system.
Imagine ive got some class with method A that takes and returns string
public class SomeClass
{
public string MethodA(string str)
{
return string.Format("SomeClass :: MethodA {0}", str);
}
}
And I want my main method to look like this
class Program
{
static void Main(string[] args)
{
var col = new SomeCollection();
col.Add<SomeClass>("url", c => c.MethodA("test")); //Bind MethodA to "url"
}
}
So my questions are:
What should be Add method signature?
How can I invoke MethodA in SomeCollection?
I guess it'll be something like
public class SomeCollection
{
public void Add<TController> (string url, Func<TController, string> exp)
{
// Add func to dictionary <url, funcs>
}
public void FindBestMatchAndExecute (Request request)
{
//Search url in collection and invoke it's method.
//Method params we can extract from request.
}
}
First, I think you want add instances of classes to a collection, not the types. Otherwise, you will need to use reflection. If my assumption is correct, then instead of declaring Func<x,y,z,...> just employ Action to be able to call any method with any numbers of parameters.
Dictionary<object, Action> tempDictionary = new Dictionary<object, Action>();
SomeClass someClass = new SomeClass();
tempDictionary.Add(someClass, () => someClass.MethodA("test"));
tempDictionary.Single(q => q.Key == someClass).Value();
but if you need return values, you will have to use Func instead of Action;
Dictionary<object, Func<string>> tempDictionary = new Dictionary<object, Func<string>>();
SomeClass someClass = new SomeClass();
tempDictionary.Add(someClass, () => someClass.MethodA("test"));
string temp = tempDictionary.Single(q => q.Key == someClass).Value();
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"