【问题标题】:Looking for a more concise way to put a C# setter into a Dictionary<> for mapping寻找一种更简洁的方法将 C# setter 放入 Dictionary<> 进行映射
【发布时间】:2020-07-29 14:21:42
【问题描述】:

这是我正在处理的大量代码的表示,它是一个映射器。最初它被写成一个大的switch 语句,但我更喜欢将映射突出为一个表格,而不是一个很长很长的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.

我似乎记得有一种更简洁的方法可以做到这一点,但我的 Google-fu 让我失望了。我可以通过将签名更改为Dictionary&lt;string, Func&lt;Foobar, decimal&gt;&gt; 来更简洁地使用 getter,然后执行以下操作:

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

但这并没有让我进入 setter。想法?

【问题讨论】:

  • 您写的内容看起来几乎像一个索引器,或者尝试使用动态调用而不使用dynamic 或从DynamicObject 继承。您可以使用x["tricycle"]=100Mx.tricycle=100M。两者的性能都会比动作字典便宜
  • 你可以用(Action&lt;Foobar, decimal&gt;)typeof(Foobar).GetProperty("One").SetMethod.CreateDelegate(typeof(Action&lt;Foobar, decimal&gt;)) 之类的东西来获取setter,但这并不更简洁

标签: c# .net reflection


【解决方案1】:

你可以这样定义你的映射:

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

【讨论】:

    猜你喜欢
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多