代码之家  ›  专栏  ›  技术社区  ›  Clinton Pierce

正在寻找一种更简洁的方法将C#setter放入字典中进行映射吗

  •  0
  • Clinton Pierce  · 技术社区  · 4 年前

    这是一个更大的代码位的表示,我正在处理的是一个映射器。最初它被写成一个大的 switch 转换

    我的第一次传球看起来像这样(来自LINQPad):

        Dictionary<string, Action<Foobar, decimal>> map
            = new Dictionary<string, Action<Foobar, decimal>> {
                    { "one", (f,d) => f.One = d },
                    { "double", (f,d) => f.Two = d },
                    { "tricycle", (f,d) => f.Three = d },
            };
        
        void Main()
        {
            Foobar obj = new Foobar();
            decimal amount = 100M;
            var x = map["one"];
            x(obj, amount);
        
            Console.WriteLine(obj.One);   // Prints 100 as expected
        }
        public class Foobar
        {
            public decimal One { get; set; }
            public decimal Two { get; set; }
            public decimal Three { get; set; }
        }
    

    Foobar decimal .

    { "one", (f,d) => f.One = d },          // It works, but … can it be better?
    

    希望在调用中作为字符串进行完全反射:

    { "one", "One" },                       // No
    { "one", nameof(Foobar.One) },          // Really, just no.
    

    我似乎记得有一种更简洁的方法可以做到这一点,但我的googlefu让我失望了。我可以去 吸气剂 通过将签名改为 Dictionary<string, Func<Foobar, decimal>>

       { "one", f.One }                        // The getter, not the setter.
    

    但这不能让我去 . 思想?

    0 回复  |  直到 4 年前
        1
  •  0
  •   Blindy    4 年前

    您可以这样定义映射:

    Mapping<Foobar, decimal> foobarMapping = new Mapping<Foobar, decimal> 
    {
        { "one", f => f.One },
        { "double", f => f.Two },
        { "tricycle", f => f.Three },
    };
    
    public class Foobar
    {
        public decimal One { get; set; }
        public decimal Two { get; set; }
        public decimal Three { get; set; }
    }
    
    void Main()
    {
        Foobar obj = new Foobar();
        obj.One = 100M;
        
        foobarMapping[obj, "one"].Dump();
        
        foobarMapping[obj, "tricycle"] = 400M;
        obj.Three.Dump();
    }
    
    class Mapping<TFrom, TTo>: IEnumerable<KeyValuePair<string, PropertyInfo>>
    {
        Dictionary<string, PropertyInfo> mapping = new Dictionary<string, PropertyInfo>();
        
        public void Add(string name, Expression<Func<TFrom, TTo>> mappingFunction) =>
            mapping.Add(name, (PropertyInfo)((MemberExpression)mappingFunction.Body).Member);
            
        public TTo this[TFrom from, string key]
        {
            get => (TTo)mapping[key].GetValue(from);
            set => mapping[key].SetValue(from, value);
        }
            
        public IEnumerator<KeyValuePair<string, PropertyInfo>> GetEnumerator() =>
            mapping.GetEnumerator();
    
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
    

    如预期,哪些产出:

    100
    400