I have a singleton that can register a func to resolve an id value for each type:
public void RegisterType<T>(Func<T, uint> func)
for example:
RegisterType<Post>(p => p.PostId );
RegisterType<Comment>(p => p.CommentId );
and then i want to resolve the id for an object, like these:
GetObjectId(myPost);
where GetObjectId definition is
public uint GetObjectId(object obj)
The question is, how can i store a reference for each func to invoke it lately. The problem is that each func has a different T type, and I can't do something like this:
开发者_如何学Goprivate Dictionary<Type, Func<object, uint>> _typeMap;
How can resolve it? Expression trees?
regards Ezequiel
You don't need Expression Trees to do it the way you are suggesting, just need to nest the function when registering it.
public void RegisterType<T>(Func<T, uint> func){
_typeMap.Add(typeof(T), obj=>func((T)obj));
}
You have two options:
Change
GetObjectId
to a generic function that takes aT
.
You can then store theFunc<T, uint>
s in a generic static class and call them by writingFuncStorage<T>.Value(obj)
.Use expression trees toCreateFunc<object, uint>
s that calls theFunc<T, uint>
(using a cast) and put those in yourDictionary<Type, Func<object, uint>>
.
EDIT: You don't need expression trees to do that; you can use a normal lambda expression which casts toT
. I was thinking of the reverse case (generating a generic delegate from a non-generic one), which does require expression trees.
public class Registration
{
public static Registration Instance = new Registration();
private Registration()
{
}
private Dictionary<Type, object> Dictionary = new Dictionary<Type, object>();
public void Register<T>(Func<T, uint> aFunc)
{
Dictionary[typeof(T)] = aFunc;
}
public uint GetId<T>(T aT)
{
var f = Dictionary[typeof(T)];
var g = (Delegate)f;
return (uint) g.DynamicInvoke(aT);
}
}
The problem is that each func has a diferent T type, and i cant do something like these:
private Dictionary<Type, Func<object, uint>> _typeMap;
I'm not sure why you say this. This works:
class Post
{
public uint PostId { get; set; }
}
static public void RegisterType<T>(Func<T, uint> getUintFromT)
{
Func<object, T> toT = (t => (T)t);
Func<object, uint> getUintFromObject =
@object => getUintFromT(toT(@object));
_typeMap.Add(typeof(T), getUintFromObject);
}
static public uint GetObjectId(object obj)
{
return _typeMap[obj.GetType()](obj);
}
Usage:
class Program
{
private static Dictionary<Type, Func<object, uint>> _typeMap
= new Dictionary<Type, Func<object, uint>>();
static void Main(string[] args)
{
RegisterType<Post>(p => p.PostId);
Post myPost = new Post();
myPost.PostId = 4;
var i = GetObjectId(myPost);
Console.WriteLine(i);
Console.ReadKey();
}
}
@SLacks, following your advise i have changed my approach to:
private Dictionary<Type, Func<object, uint>> _typeMap;
public void RegisterType<T>(uint typeId, Func<T, uint> func)
{
_typeMap[typeof(T)] = (o) => func((T)o);
}
public uint GetObjectId(object obj)
{
return _typeMap[obj.GetType()](obj);
}
thanks!
I cant change GetObjectId
to GetObjectId<T>
because i don´t known the type on runtime.
So, i have changed the dictionary definition to:
private Dictionary<Type, Delegate> _typeMap
and then invoke it via Reflection:
public uint GetObjectId(object obj)
{
uint id = 0;
var objType = obj.GetType();
// busco si el type está registrado
if (_typeMap.Keys.Contains(objType))
{
id = (uint) _typeMap[objType].Method.Invoke(obj, new object[] { obj } );
}
return id;
}
Thank you all so much
精彩评论