【问题标题】:C# Binding data objectsC# 绑定数据对象
【发布时间】:2013-06-21 21:42:00
【问题描述】:

我需要两个相似对象之间的绑定(C#):

public class TypeA
{
     public int I;
     public string S;
}

public class TypeB
{
     public IntField I;
     public StringField S;
}

当 TypeA 中的字段发生变化时,我需要更新 TypeB 中的匹配字段。

IntField 是一个具有 int 类型的 Value 字段的对象,因此更新 TypeB 可以写成:

bInstance.I.Value = aInstance.I;

如果我理解正确,如果我使用 INotifyPropertyChanged 将 TypeB 绑定到 TypeA,则会导致样板:

aInstance.PropertyChanged += (sender, args) =>
{
    if (args.PropertyName == "I")
        this.I.Value = sender.I;
    if (args.PropertyName == "S")
        this.S.Value = sender.S;
};

还有:

  • 我可以访问这两种类型的代码,我宁愿不更改 TypeB。
  • 我有大约 15 对类型,例如 TypeA 和 TypeB - 我想避免使用样板。
  • 性能非常重要,因此反射不是首选选项。
  • 也许静态反射是一种选择?我听说过,但我不确定:
    • 如何在没有样板的情况下使用它。
    • 它的性能。
    • 将它用于相同类型对的不同实例(即 a1Instance->b1Instance、a2Intance->b2Instance 等)。

编辑:

IntField 是一个类。 它用于系统中存在的另一种类型的数据绑定(复杂,整个系统都依赖于此)。它继承自表示通用可绑定字段的类。这是其中的一部分:

public class IntField : GeneralField
{
    private int _value;
    public int Value
    {
        get { return _value; }
        set
        {
            IsDirty = true;
            _value = value;
        }
    }

    // ... a couple of abstract method implementations go here (setting _value, and getting value in a non-type specific way)
}

【问题讨论】:

  • 好吧,当它们作为字段保留时,您将无法执行 任何操作 - 我假设您可以将它们设置为属性?你还能描述(或更好:显示)IntField / StringField 吗?他们是struct 还是class? (即哪个?)这可能很重要。还;你究竟想在这里做什么IntField / StringField目的是什么?
  • 谢谢马克!我可以将 TypeA 的字段设置为属性,并且我通过一些说明更新了这个问题。这有点疯狂,但我有 IntField 和 StringField 的客户端-服务器数据绑定,现在我需要另一种类型的绑定用于我应该使用的新服务器框架。

标签: c# data-binding static-reflection


【解决方案1】:

如果您不想要大量手动编码,那么基于反射或基于元编程的东西将是您的最佳选择。例如:

static void Entwine(INotifyPropertyChanged source, object target)
{
    source.PropertyChanged += (sender,args) =>
    {
        var prop = target.GetType().GetProperty(args.PropertyName);
        if(prop != null)
        {
            var field = prop.GetValue(target) as GeneralField;
            if(field != null)
            {
                var newVal = source.GetType().GetProperty(args.PropertyName)
                                   .GetValue(source);
                field.SetValue(newVal); // <=== some method on GeneralField
            }
        }
    };
}

在很多情况下这会很好,但如果反射确实是个问题,FastMember 之类的工具可以提供帮助:

static void Entwine(INotifyPropertyChanged source, object target)
{
    var sourceAccessor = ObjectAccessor.Create(source);
    var targetAccessor = ObjectAccessor.Create(target);
    source.PropertyChanged += (sender, args) =>
    {
        var field = targetAccessor[args.PropertyName] as GeneralField;
        if (field != null)
        {
            var newVal = sourceAccessor[args.PropertyName];
            field.SetValue(newVal);
        }
    };
}

这比反射要快得多——它使用了很多技巧来避免痛苦。这只是需要类似的东西:

abstract class GeneralField
{
    // ...
    public abstract void SetValue(object value);
}
class Int32Field : GeneralField
{
    // ...
    public override void SetValue(object value)
    {
        Value = (int)value;
    }
}

当然还有你的INotifyPropertyChanged 实现,例如:

public class TypeA : INotifyPropertyChanged
{
    private int i;
    private string s;
    public int I
    {
        get { return i; }
        set { SetField(ref i, value); }
    }
    public string S
    {
        get { return s; }
        set { SetField(ref s, value); }
    }
    private void SetField<T>(ref T field, T value,
        [CallerMemberName]string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            var handler = PropertyChanged;
            if (handler != null) handler(
                this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

【讨论】:

  • 太棒了!我了解如何使用闭包和包装器来解决问题。顺便说一句,你用“SetValue”方法把它钉牢了,我已经有了。 :) 你统治!我很好奇这些技巧。来源在这里:code.google.com/p/fast-member
  • @Tom 是的,这就是来源;它使用每种类型的 IL 生成(然后将其缓存并重新用于该类型的所有后续出现);他们的关键点在于它将基于字符串的成员访问转变为紧密的 IL
猜你喜欢
  • 2010-10-17
  • 1970-01-01
  • 2015-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
相关资源
最近更新 更多