如何仅初始化具有值的属性?

时间:2016-09-01 13:22:18

标签: c# reflection properties

我有一个继承自 System.Windows.Forms.Control CustomControl 类。 我还将创建一个名为 GraphicsData 的新类,它将包含有关我的CustomControl的所有图形信息(我需要这个,因为它更容易序列化数据以将其保存在DB,json中,等)

CustomControl对象将在初始化时(在构造函数中)获取GraphicsData,并且我希望它获取在GraphicsData中具有值的所有属性(有时我不想初始化GraphicsData中的所有属性)我希望它们保持System.Windows.Forms.Control类的默认值。

问题在于,大部分属性不可空,我无法检查它们是否为空,因此我无法做到这一点:

customControl.BackColor = graphicsData.BackColor.HasValue ? graphicsData.BackColor.Value : BackColor;

如果我创建自己的Nullable类,我当然可以解决这个问题,但这真的很丑陋并且难以理解代码。此外,在需要时添加新属性非常困难。

现在,我做了什么,我认为这是一个更清洁的方式如下:

GraphicsData 类:

public class GraphicsData : INotifyPropertyChanged
{
    private readonly List<string> _initializedProperties = new List<string>();
    public List<string> InitializedProperties { get { return _initializedProperties; } }

    public event PropertyChangedEventHandler PropertyChanged;

    private Size _size;
    private Point _location;
    private AnchorStyles _anchor;
    private Color _backColor;
    private Image _backgroundImage;
    private Cursor _cursor;
    private Font _font;
    private Color _foreColor;
    private bool _enabled;
    private bool _visible;

    public Size Size
    {
        get { return _size; }
        set
        {
            _size = value;
            OnPropertyChanged("Size");
        }
    }

    public Point Location
    {
        get { return _location; }
        set
        {
            _location = value;
            OnPropertyChanged("Location");
        }
    }

    public AnchorStyles Anchor
    {
        get { return _anchor; }
        set
        {
            _anchor = value;
            OnPropertyChanged("Anchor");
        }
    }

    public Color BackColor
    {
        get { return _backColor; }
        set
        {
            _backColor = value;
            OnPropertyChanged("BackColor");
        }
    }

    public Image BackgroundImage
    {
        get { return _backgroundImage; }
        set
        {
            _backgroundImage = value;
            OnPropertyChanged("BackgroundImage");
        }
    }

    public Cursor Cursor
    {
        get { return _cursor; }
        set
        {
            _cursor = value;
            OnPropertyChanged("Cursor");
        }
    }

    public Font Font
    {
        get { return _font; }
        set
        {
            _font = value;
            OnPropertyChanged("Font");
        }
    }

    public Color ForeColor
    {
        get { return _foreColor; }
        set
        {
            _foreColor = value;
            OnPropertyChanged("ForeColor");
        }
    }

    public bool Enabled
    {
        get { return _enabled; }
        set
        {
            _enabled = value;
            OnPropertyChanged("Enabled");
        }
    }

    public bool Visible
    {
        get { return _visible; }
        set
        {
            _visible = value;
            OnPropertyChanged("Visible");
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        if (!_initializedProperties.Contains(propertyName))
            _initializedProperties.Add(propertyName);

        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

在我的自定义控件中,我有一个方法:

public void LoadGraphics()
    {
        var initializedProperties = graphics.InitializedProperties;
        foreach (string propertyName in initializedProperties)
        {
            var value = graphics.GetType()
                                .GetProperty(propertyName)
                                .GetValue(graphics, null);
            _customControl.GetType()
                          .GetProperty(propertyName)
                          .SetValue(_customControl, value, null);
        }
    }

基本上,我创建了一个名为 InitializedProperties 列表,并在属性&#34; set&#34;我在列表中添加属性。 之后,在我的 CustomControl 中使用反射,我可以加载所有已初始化的属性。

我实现了 INotifyPropertyChanged ,因为我还希望每次在GraphicsData中更改属性时都更改customControl属性。

这是做我想要的正确方法吗?我不认为反射代码是可读的,我担心性能。

1 个答案:

答案 0 :(得分:3)

使用可空值是一种更容易实现此目的的方法。

C#已经有一个内置的Nullable类,但它还提供了一种简单的方法,可以使值可为空,而不会导致Nullable类引入的过多冗长:?。< / p>

通过将?运算符附加到值类型,可以使所有值都可为空:

private Size? _size;
private Point? _location;
private AnchorStyles? _anchor;
private Color? _backColor;
private Image _backgroundImage;
private Cursor _cursor;
private Font _font;
private Color? _foreColor;
private bool? _enabled;
private bool? _visible;

您的LoadGraphics方法可以轻松检查GraphicsData属性是否具有非null值,如果是,则设置相应的控件属性。

public void LoadGraphics(GraphicsData gfx)
{
    // It may be permissible to utilize a null value for BackgroundImage!
    // In this case, utilizing a separate field (IsBackgroundImageSet) may be a necessary
    if (gfx.BackgroundImage != null) { _customControl.BackgroundImage = gfx.BackgroundImage; }

    if (gfx.Size != null) { _customControl.Size = gfx.Size.Value; }
    if (gfx.Location != null) { _customControl.Location = gfx.Location.Value }
    if (gfx.Anchor != null) { _customControl.Anchor = gfx.Anchor.Value; }
    if (gfx.BackColor != null) { _customControl.BackColor = gfx.BackColor .Value; }
    if (gfx.Cursor != null) { _customControl.Cursor = gfx.Cursor; }
    if (gfx.Font != null) { _customControl.Font = gfx.Font; }
    if (gfx.Color != null) { _customControl.Color = gfx.Color.Value; }
    if (gfx.Enabled != null) { _customControl.Enabled = gfx.Enabled.Value; }
    if (gfx.Visible != null) { _customControl.Visible = gfx.Visible.Value; }
}