【问题标题】:references to Func's of different types对不同类型的 Func 的引用
【发布时间】:2011-02-28 14:17:52
【问题描述】:

我有一个单例,可以注册一个函数来解析每种类型的 id 值:

public void RegisterType<T>(Func<T, uint> func)

例如:

RegisterType<Post>(p => p.PostId );
RegisterType<Comment>(p => p.CommentId );

然后我想解析一个对象的 id,如下所示:

GetObjectId(myPost);

GetObjectId 定义在哪里

public uint GetObjectId(object obj)

问题是,我怎样才能为每个函数存储一个引用以便最近调用它。 问题是每个 func 都有不同的 T 类型,我不能这样做:

private Dictionary<Type, Func<object, uint>> _typeMap;

如何解决?表达式树?

问候 以西结

【问题讨论】:

  • PostComment 是否可以从具有 Id 属性的公共接口派生?
  • 不,它们不能从通用接口派生。

标签: c# .net-3.5 lambda expression-trees


【解决方案1】:

你不需要表达式树来按照你建议的方式来做,只需要在注册时嵌套函数。

public void RegisterType<T>(Func<T, uint> func){
             _typeMap.Add(typeof(T), obj=>func((T)obj));
}

【讨论】:

    【解决方案2】:

    你有两个选择:

    1. GetObjectId 更改为采用 T 的通用函数。
      然后您可以store the Func&lt;T, uint&gt;s in a generic static class 并通过写FuncStorage&lt;T&gt;.Value(obj) 给他们打电话。

    2. 使用表达式树创建调用Func&lt;T, uint&gt;(使用强制转换)的Func&lt;object, uint&gt;s,并将它们放入您的Dictionary&lt;Type, Func&lt;object, uint&gt;&gt;
      编辑:你不需要表达式树来做到这一点;您可以使用转换为 T 的普通 lambda 表达式。我在考虑相反的情况(从非泛型委托生成泛型委托),这确实需要表达式树。

    【讨论】:

    • 感谢 SLaks,我无法将 GetObjectId 更改为 GetObjectId,因为我不知道运行时的类型。
    【解决方案3】:
    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);
            }
        }
    

    【讨论】:

    • DynamicInvoke 很慢,但在@Pedro 的解决方案中没有必要。在此示例中,实际上可以知道类型,例如 var g = (Func&lt;T,unit&gt;)f; 然后 return g(aT)。虽然这可能不适用于@eze1981,但它可能适用于其他人。
    【解决方案4】:

    问题是每个函数都有一个 不同的T型,我做不到 像这样的:

    private Dictionary<Type, Func<object, uint>> _typeMap;
    

    我不知道你为什么这么说。这有效:

    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);
    }
    

    用法:

    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();
    
        }
    }
    

    【讨论】:

      【解决方案5】:

      @SLacks,根据您的建议,我已将方法更改为:

      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);
      }
      

      谢谢!

      【讨论】:

        【解决方案6】:

        我无法将GetObjectId 更改为GetObjectId&lt;T&gt;,因为我不知道运行时的类型。

        所以,我已将字典定义更改为:

        private Dictionary<Type, Delegate> _typeMap 
        

        然后通过反射调用它:

        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;
        }
        

        非常感谢大家

        【讨论】:

        • 看我的回答。您可以在运行时不知道类型的情况下调用 GetId。它会被推断出来。
        • 你应该让字典保存Func&lt;object, uint&gt;,方法是创建一个将对象参数转换为T的lambda。这会更快。
        • @Pedro:错了。类型推断只能在编译时发生。
        • @SLaks 是的,推理发生在编译时。但是看看我的代码。它会起作用的。
        • @Pedro 编译时的推断将是 GetId&lt;object&gt; 因此当 Dictionary[typeof(object)] 将无法找到任何东西。实际上,由于您使用了DynamicInvoke,因此您根本不需要在 GetId 上使用泛型,因此Dictionary[aT.GetType())] 会使其工作,尽管它会很慢,与@eze1981 解决方案一样慢,因为DynamicInvoke 只是一个简短的切入Method.Invoke
        猜你喜欢
        • 1970-01-01
        • 2018-03-18
        • 2013-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-17
        • 1970-01-01
        相关资源
        最近更新 更多