jjzjj

c# - 委托(delegate)为属性 : Bad Idea?

coder 2024-05-21 原文

考虑以下控件(为简洁起见被截断):

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

    }
}

此控件还有更多内容,但足以说明它允许用户添加、编辑和删除 Dictionary 中的条目。为了确定它是否应该允许用户编辑或删除条目,它使用委托(delegate)方法properties、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());
    }
}

我发现这个设计既令人满意又令人担忧。一方面,它似乎使用最简单的可行解决方案来解决问题(它当然很好地分离了关注点)。另一方面,我有一个挥之不去的担忧,我不正确地使用委托(delegate),应该使用一个事件,而不是(即使我确实不需要需要多个监听器,只需要调用者告诉我是否该项目是可编辑的)。

然后,另一方面,有可能存在一种完全不同的设计,我什至没有考虑过它可能会以非常优越的方式解决问题。

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

最佳答案

我建议对这两种方法使用一个接口(interface)。这样就干净多了:

interface ICantThinkOfAGoodName
{
    bool CanEdit(string item);
    bool CanDelete(string item);
}

您可以创建类似于许多 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);
    }
}

像这样使用它:

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();

}

顺便说一句:我在这里使用属性注入(inject),因为它是一个控件。通常,我会在 ConfigurationManagerControl 的构造函数中传递 ICantThinkOfAGoodName 依赖项。

关于c# - 委托(delegate)为属性 : Bad Idea?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7575059/

有关c# - 委托(delegate)为属性 : Bad Idea?的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  4. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  5. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  8. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  9. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

    所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

  10. ruby - 获取数组中的值并最小化某个类属性的最优雅的方法是什么? - 2

    假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)

随机推荐