繁体   English   中英

C#绑定数据对象

[英]C# Binding data objects

我需要在两个相似的对象(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)
}

如果您不希望进行大量手动编码,那么基于反射或基于元编程的方法将是您的最佳选择。 例如:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM