使用反射初始化对象的自动属性 ​​- 有什么注意事项吗? [英] Initializing autoproperties of object using Reflection - any caveats?

查看:62
本文介绍了使用反射初始化对象的自动属性 ​​- 有什么注意事项吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近编写了两个类和一个接口作为实现这个答案的一种方式我的问题.

I recently wrote two classes and an interface as a way to implement the answer to this question of mine.

第一个类是 Notifier 泛型类:

The first class is the Notifier generic class:

public interface INotifier { }
public class Notifier<T> : Observable,INotifier where T:new()
{
    public Notifier()
    {            
        V = new T();
    }
    private T _ValueBacker;
    public T V
    {
        get { return _ValueBacker; }
        set
        {
            _ValueBacker = value;
            OnPropertyChanged(() => V);
        }
    }
}

这里的 Observable 基类只是一个实现 INotifyPropertyChanged 并定义了 OnPropertyChanged 方法的类.

The Observable base class here is just a class that implements INotifyPropertyChanged and defines an OnPropertyChanged method.

多亏了那个类,我现在可以像这样定义 Silverlight/WPF ViewModel:

Thanks to that class, I can now define a Silverlight/WPF ViewModel like this:

public class Person : ViewModelBase
{
    Notifier<string> Name {get;set;}
    Notifier<string> Surname {get;set;}
    Notifier<int> Age {get;set;}
}

代替:

public class Person : Observable
{
    private string _Name;
    public string Name 
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name=value;
            OnPropertyChanger(()=>Name);
        }
    }
    privaate string _Surname;
    public string Surname 
    {
        get
        {
            return _Surname;
        }
        set
        {
            _Surname=value;
            OnPropertyChanger(()=>Surname);
        }
    }
    private int _Age;
    public int Age
    {
        get
        {
            return _Age;
        }
        set
        {
            _Age=value;
            OnPropertyChanger(()=>Age);
        }
    }
}

如您所见,新代码更加简洁,并且更不容易出现编码错误(或拼写错误).我在 XAML 中要做的就是绑定到MyPerson.V"而不是MyPerson".但是,由于没有任何方法可以实现自动属性的初始化程序,因此我必须在构造函数中初始化每个属性.在某些情况下,我跳过了初始化程序,这导致了一些运行时错误.所以,为了解决这个问题,在 ViewModelBase 类的构造函数中,我添加了这个循环:

As you can see, the new code is much more concise and much less coding-error (or typo) prone. All I have to do in my XAML is to bind to "MyPerson.V" instead of "MyPerson". However, since there aren't any ways to implement initializers for autoproperties, I had to initialize every property in the constructor. In some cases, I skipped the initializers and that led to some runtime errors. So, to take care of that, in the constructor of the ViewModelBase class, I added this loop:

    public ViewModelBase()
    {
        foreach(var notifierProperty in this.GetType().GetProperties().Where(c=>c.PropertyType.GetInterfaces().Any(d=>d==typeof(INotifier))))
        {                
            notifierProperty.SetValue(this, notifierProperty.PropertyType.GetConstructor(System.Type.EmptyTypes).Invoke(null), null);
        }
    }

这样做的目的是,每当您实例化 ViewModelBase 派生类时,构造函数都会遍历属性,并为每个 Notifier 类型的属性调用构造函数.

What this does is, whenever you instantiate a ViewModelBase derived class, the constructor loops through the properties, and invokes the constructor for each Notifier type property.

这是邪恶的吗?将来会以这种方式使用反射来困扰我吗?有什么我应该注意的性能问题吗?

Is this evil? Will using reflection this way come back to haunt me in the future? Are there any performance hits I should be aware of?

推荐答案

我认为这很好.我有一些信息要补充:

I think that's fine. I have some bits of information to add:

  1. 您可以通过调用 Activator.Create(myType) 来创建具有普通构造函数的类型,这意味着您不必获取构造函数.
  2. 我相信至少对于 Silverlight,所有用您的 hack 初始化的属性都需要公开.
  3. 有一个名为 ReactiveProperty 的库,它定义了一个类 ReactiveProperty<T> 与您的 Notifier 非常相似.
  1. You can create types with trivial constructors by calling Activator.Create(myType), which means you don't have to fetch a constructor.
  2. I believe at least for Silverlight, all properties initialized with your hack need to be public.
  3. There is a library called ReactiveProperty, that defines a class ReactiveProperty<T> very similar to your Notifier<T>.

您将绑定它的 Value 属性:

You will bind against it's Value property:

public class ReactiveProperty<T> : IObservable<T>, IDisposable, INotifyPropertyChanged, IReactiveProperty, INotifyDataErrorInfo
{
    public T Value
    {
        get { return latestValue; }
        set { anotherTrigger.OnNext(value); }
    }

    // ...
}

setter 中的调用最终导致对 INotifyPropertyChanged.PropertyChanged 的相应调用.

The call in the setter eventually leads to the respective call to INotifyPropertyChanged.PropertyChanged.

ReactiveProperty反应式扩展,库所依赖的.除此之外,作者基本上做了你所做的,但没有构造函数中的初始化技巧.

ReactiveProperty<T> also is an observable in the sense of reactive extensions, on which the library depends. Other than that, the author basically does what you do, but without the initialization hack in the constructor.

这篇关于使用反射初始化对象的自动属性 ​​- 有什么注意事项吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆