C# 一个类上同一接口的多个实现的替代方案

C# 一个类上同一接口的多个实现的替代方案,c#,interface,implementation,webforms,facet,C#,Interface,Implementation,Webforms,Facet,假设有一个公共用户页面控件,该控件提供操作并在大多数应用程序页面上重用。常见的操作有:保存、取消、重置、发送等。目前大约有10个 特定的操作状态通常但不一定取决于页面上显示的实体及其状态。在创建新实体实例的情况下,可以显示并启用“保存”和“取消”。但是,当我们编辑现有的一个保存时,取消和重置可以是主动显示的操作 操作公共控件和页面之间的通信 因为这个带有动作的公共控件是状态解耦的,并且不知道页面的上下文(或者实体类型和状态),所以我决定给它注入钩子,这样页面就可以提供公共控件将使用的动作按钮获取

假设有一个公共用户页面控件,该控件提供操作并在大多数应用程序页面上重用。常见的操作有:保存、取消、重置、发送等。目前大约有10个

特定的操作状态通常但不一定取决于页面上显示的实体及其状态。在创建新实体实例的情况下,可以显示并启用“保存”和“取消”。但是,当我们编辑现有的一个保存时,取消和重置可以是主动显示的操作

操作公共控件和页面之间的通信 因为这个带有动作的公共控件是状态解耦的,并且不知道页面的上下文(或者实体类型和状态),所以我决定给它注入钩子,这样页面就可以提供公共控件将使用的动作按钮获取程序

我没有定义事件和委托,而是决定做一个基本相同场景的简化类型。我刚刚使用了
Func
属性,但它们可以很容易地转换为事件/委托。目前,它们的定义仍然是这样的(例如发送操作):

private Func DefaultState=()=>false;
私有函数是可见的;
公共职能是可见的
{
private get{return isSendVisible??DefaultState;}
设置{isSendVisible=value;}
}
私人职能部门可申请;
公共职能不可撤销
{
private get{return isSendEnabled??DefaultState;}
设置{isSendEnabled=value;}
}
问题是我在接口中定义了以下两个属性:

public interface ISendActionProvider
{
    Func<bool> IsSendVisible { set; }
    Func<bool> IsSendEnabled { set; }
}
公共接口ISendActionProvider
{
Func IsSendVisible{set;}
Func是可归属的{set;}
}
我的公共控件实现了这个界面(以及其他操作的界面),但是其他控件(甚至页面本身)可以提供相同的界面,因此相同的按钮可以显示在多个地方,并且可以重用相同的操作状态机制。页面只需在初始化期间将其getter绑定到提供程序,这样操作提供程序就可以适当地设置操作的状态

问题 问题是,对于每个新操作,我都必须为其添加相同的接口和实现,这会导致相当多的半重复代码

如果我能有一个接口并为每个动作实现它,这样它就可以由一个类(动作提供者类——在我的例子中是提供这些动作的公共控件)实现多次,那就太好了。在C#中,唯一可行的方法是使用通用接口,然后根据需要提供尽可能多的实现。但是我没有区分泛型类型来提供多个泛型接口实现

public interface IActionProvider // multiple inplementations?
{
    Func<bool> IsActionVisible { set; }
    Func<bool> IsActionEnabled { set; }
}
公共接口IActionProvider//多个输入实现?
{
Func IsActionVisible{set;}
Func IsActionEnabled{set;}
}
实现的工作方式(如上所示)是每个操作都定义了其默认行为,但特定页面可以通过为特定操作提供自己的getter来覆盖该行为,以提供其状态

我有哪些可能合并我的代码? 我想要的是某种通用属性提供程序,可以在初始化绑定期间调用:

(provider as IActionProvider<TSend>).IsActionVisible<TSend> = this.IsSendVisible;
(提供者作为IActionProvider)。IsActionVisible=this.IsSendVisible;
但正如前面提到的,我没有这样的区分泛型类型。

一个可能的解决方案 注意:我自己用一个可能的解决方案来回答这个问题,这个解决方案我并不喜欢,但我会按照要求去做。我还在等待更好的建议

没有几个接口及其实现,我只能有一个定义稍有不同的接口:

public interface IActionProvider
{
    void SetVisibleGetter(ActionType type, Func<bool> getter);
    void SetEnabledGetter(ActionType type, Func<bool> getter);
}

您可以提供默认实现,并使用继承覆盖默认实现

例如

公共类SubmitActionProvider:ActionProvider
{        
公共覆盖函数IsActionVisible
{
得到
{ 
控制台。书面形式(“提交”);
返回null;
}
}
}
公共类CancelActionProvider:ActionProvider
{
公共覆盖函数IsActionVisible
{
得到
{
控制台。写入线(“取消”);
返回null;
}
}
}
公共类ActionProvider
{
公共虚拟函数IsActionVisible{get{Console.WriteLine(“默认实现”);返回null;}
公共虚拟函数已启用{set{}
}

当您只考虑类模型而不是实际的控件实现时,这是一个很好的建议。你看,个人行为并不是真正的个人行为。它们是日常的Asp.net链接按钮。它们包含在(我们这样称呼它)
CommonActions.ascx
中。这个特定控件的codebehind类为其他操作链接/按钮实现特定的接口
ISendActionProvider
和其他。我的页面只与整个
通用操作
控件进行通信,而不是与控件上的单个操作进行通信。
public interface IActionProvider
{
    void SetVisibleGetter(ActionType type, Func<bool> getter);
    void SetEnabledGetter(ActionType type, Func<bool> getter);
}
private IDictionary<ActionType, Func<bool>> isActionVisible = new Dictionary<ActionType, Func<bool>> {
    { ActionType.Cacel, AlwaysFalse }
    { ActionType.Send, AlwaysFalse },
    ...
};

public void SetVisibleGetter(ActionType type, Func<bool> getter)
{
    this.isActionVisible[type] = getter ?? this.isActionVisible[type];
}

...
linkSend.Visible = this.isActionVisible[ActionType.Send]();
public class SubmitActionProvider:ActionProvider
{        
    public override Func<bool>  IsActionVisible
    {
         get 
         { 
            Console.WriteLine("submit");
                  return null;
         }
    }
}

public class CancelActionProvider : ActionProvider
{
    public override Func<bool> IsActionVisible
    {
        get
        {
            Console.WriteLine("cancel");
            return null;
        }
    }
}


public class ActionProvider
{
    public virtual Func<bool> IsActionVisible { get { Console.WriteLine("Default implementation"); return null; } }
    public virtual Func<bool> IsActionEnabled { set { } }
}