代表作为属性:坏主意?

Mik*_*fer 15 c# delegates software-design

考虑以下控件(为简洁而剪切):

public partial class ConfigurationManagerControl : UserControl
{

    public Func<string, bool> CanEdit { get; set;}
    public Func<string, bool> CanDelete { get; set; }

    public Dictionary<string, string> Settings
    {
        get { return InnerSettings; }
        set
        {
            InnerSettings = value;
            BindData();
        }
    }
    private Dictionary<string, string> InnerSettings;

    private void OnListIndexChanged(object sender, EventArgs e)
    {
        this.EditButton.Enabled = false;
        this.DeleteButton.Enabled = false;

        var indices = this.List.SelectedIndices;
        if (indices.Count != 1)
        {
            return;
        }

        var index = indices[0];
        var item = this.List.Items[index];

        if (this.CanEdit != null)
        {
            this.EditButton.Enabled = this.CanEdit(item.Text);
        }

        if (this.CanDelete != null)
        {
            this.DeleteButton.Enabled = this.CanDelete(item.Text);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

这个控件还有更多内容,但足以说它允许用户添加,编辑和删除Dictionary <string,string>中的条目.为了确定它是否应允许用户编辑或删除条目,它使用委托方法属性 CanDelete和CanEdit,它们由托管它的表单或控件提供:

public class SetupWizard : Form
{
    public SetupWizard()
    {
        InitializeComponent();

        this.SettingManager.CanEdit = CanEditSetting;
        this.SettingManager.CanDelete = CanDeleteSetting;
    }

    private static bool CanEditSetting(string item)
    {
        var lockedSettings = new[] { "LicenseHash", "ProductHash" };
        return !lockedSettings.Contains(item.ToLower());
    }

    private static bool CanDeleteSetting(string item)
    {
        var lockedSettings = new[] {
                                        "LicenseHash",
                                        "ProductHash", 
                                        "UserName", 
                                        "CompanyName"
                                    };
        return !lockedSettings.Contains(item.ToLower());
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现这种设计既令人满意又令人担忧.一方面,似乎使用最简单的解决方案来解决问题(它确实很好地区分了问题).在另一方面,我有我使用不当的代表,应使用一个事件,而是这唠叨的关注(尽管我并不需要多个监听器,只需要来电告诉我,如果项目可编辑).

然后,另一方面,有一个完全不同的设计,我甚至没有考虑过可能以一种非常优越的方式解决问题.

所以.这种设计在技术上是否正确,可维护且灵活?或者我应该做得更好?

Dan*_*rth 11

我建议使用这两种方法的接口.那更清洁了:

interface ICantThinkOfAGoodName
{
    bool CanEdit(string item);
    bool CanDelete(string item);
}
Run Code Online (Sandbox Code Playgroud)

您可以创建类似于许多MVVM框架中使用的RelayCommand的东西:

public class RelayObject : ICantThinkOfAGoodName
{
    public RelayObject() : this(null, null) {}
    public RelayObject(Func<string, bool> canEdit, Func<string, bool> canDelete)
    {
        if(canEdit == null) canEdit = s => true;
        if(canDelete == null) canDelete = s => true;

        _canEdit = canEdit;
        _canDelete = canDelete;
    }

    public bool CanEdit(string item)
    {
        return _canEdit(item);
    }
    public bool CanDelete(string item)
    {
        return _canDelete(item);
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

public SetupWizard()
{
    InitializeComponent();

    this.SettingManager.PropertyName = new RelayObject(CanEditSetting, 
                                                       CanDeleteSetting);
    // or (all can be deleted)
    this.SettingManager.PropertyName = new RelayObject(CanEditSetting, null);
    // or (all can be edited)
    this.SettingManager.PropertyName = new RelayObject(null, CanDeleteSetting);
    // or (all can be edited and deleted)
    this.SettingManager.PropertyName = new RelayObject();

}
Run Code Online (Sandbox Code Playgroud)

BTW:我在这里使用Property注入,因为它是一个控件.通常,我会ICantThinkOfAGoodName在构造函数中传递依赖项ConfigurationManagerControl.