C# 泛型基类重写非泛型基类函数模式?(.NET)

C# 泛型基类重写非泛型基类函数模式?(.NET),c#,.net,vb.net,generics,design-patterns,C#,.net,Vb.net,Generics,Design Patterns,我想知道是否有人对解决以下设计问题有好的建议/模式。我有指挥类的继承权。在最抽象的层次上,我有一个ICommand接口。执行ICommand的RunCommand()函数的结果是一个对象。不同的命令将有不同的结果类型,因此这是一个适当的抽象 在建立继承权的过程中,使用泛型变得更为可取。我创建了一个Generic.ICommand(属于TResult)接口 我希望所有命令都有一些常见的模板代码,如Run、TryRun、BeginRun、BeginTryRun等,因此我创建了一个BaseComman

我想知道是否有人对解决以下设计问题有好的建议/模式。我有指挥类的继承权。在最抽象的层次上,我有一个ICommand接口。执行ICommand的RunCommand()函数的结果是一个对象。不同的命令将有不同的结果类型,因此这是一个适当的抽象

在建立继承权的过程中,使用泛型变得更为可取。我创建了一个Generic.ICommand(属于TResult)接口

我希望所有命令都有一些常见的模板代码,如Run、TryRun、BeginRun、BeginTryRun等,因此我创建了一个BaseCommand类来提供所有这些,并实现了非通用的ICommand接口。但是,BaseCommand不知道如何实际执行任何操作,因此所有这些命令最终都会调用一个名为InternalRunCommand的受保护抽象函数。这一切都很好

现在我想创建该类的通用版本:BaseCommand(of T)。它继承自BaseCommand,还实现了通用ICommand(Of T)接口。这是可行的,但现在存在一个差异:internalrun命令

在非泛型版本中,InternalRunCommand返回一个对象。在我的泛型BaseCommand(Of T)类中,我想用一个以类型T返回结果的泛型版本重载它。不幸的是,VB.NET/C#编译器不允许您提供方法重载,其中唯一的区别是返回类型

由于这是一个受保护的函数,它最终不会对整个API产生太大的影响,但它仍然让我恼火,因为我没有一个美观的解决方案来解决这种体系结构

目前,我已重写BaseCommand(Of T)类中的非泛型InternalRunCommand,以便它调用一个新的受保护的抽象OnRunCommand函数,该函数接受相同的参数,但返回类型为T的结果。InternalRunCommand也已声明为不可重写。这可能是我能得到的最接近的了——但我想看看是否有更好的想法

编辑:我已根据要求提供了一份代码的简化副本,以便您可以更好地可视化问题:

Public Interface ICommand
    Property Name as String
    Property Description As String
    Property ResultType as Type
    Function RunCommand(target as Device) As Object
    Function TryRunCommand(target as Device, Byref result as Object) AS Boolean
    Function BeginRunCommand(target as Device) as Task(Of Object)
    Function BeginTryRunCommand(target as Device) As Task(of Boolean)
End Interface

Namespace Generic
Public Interface ICommand(Of TResult)
    Function RunCommand(target as Device) as T
    Function BeginRunCommand(target as Device) As Task(Of T)
End Interface
End Namespace

Public MustInherit Class BaseCommand
    Implements ICommand

    Public Function RunCommand(target as Device) As Object Implements ICommand.RunCommand
        Return InternalRunCommand(device)
    End Function

    Public Function BeginRunCommand(target as Device) As Task(of Object) Implements ICommand.BeginRunCommand
        Return Task(Of Object).Factory.StartNew( Function() InternalRunCommand(target))
    End Function

    ' Other boiler plate code goes here'

    Protected MustOverride Function InternalRunCommand(target as Device) As Object

End Class

Namespace Generic
Public Class BaseCommand(Of TResult)
    Inherits BaseCommand
    Implements ICommand(Of TResult)

    Public Function BeginRunCommand(target as Device) As Task(of TResult) Implements ICommand(Of TResult).BeginRunCommand
        Return Task(Of TResult).Factory.StartNew( Function() OnRunCommand(target))
    End Function

    Protected NotOverridable Overrides Function InternalRunCommand(target as Device) As Object
        ' Re-route to the generic version'
        Return OnRunCommand(device)
    End Function

    Protected MustOverride Function OnRunCommand(target as Device) As T
End Class

我想我已经找到了一个很好的模式,它允许您用泛型函数覆盖此类函数的非泛型版本,并且没有任何像我在OP中那样凌乱的包装函数

我已将受保护的抽象InnerRunCommand函数替换为同名的受保护只读属性。此属性的类型为Func(用于ICommand、设备、对象)。我修改了BaseCommand类的构造函数以接受这样一个Func对象

在Generic.BaseCommand(Of T)类中,我可以使用Func(Of ICommand,Device,T)类型的类似属性来隐藏InnerRunCommand。(T的)Generic.BaseCommand的构造函数类似地接受这样一个Func对象,并将该对象传递回非Generic BaseCommand构造函数,而不发出以下问题:)

我正在修改我的体系结构以支持这个新模式,如果我遇到任何问题,我会告诉大家。我欢迎对这种方法的任何批评,并欢迎其他答案:)

编辑:我在下面构建了一个提议模式的简单示例。我用C#而不是VB.NET编写了它。在C#中强制转换FUNC对象需要做更多的工作(VB.NET在幕后为您处理这一点)。但是,在这两种语言中,使用这些匿名函数可以保持API的干净性和可扩展性

public interface ICommand
{
    object Execute();
    Boolean TryExecute(out object result);
    Task<object> BeginExecute();        
}

namespace Generic
{
    public interface ICommand<TResult> : ICommand
    {
        new TResult Execute();
        Boolean TryExecute(out TResult result);
        new Task<TResult> BeginExecute();
    }
}

public class Command : ICommand
{
    private Func<ICommand, object> _execFunc = null;
    protected Func<ICommand, object> ExecFunc { get { return _execFunc; } }

    public Task<object> BeginExecute()
    {
        return Task<object>.Factory.StartNew(() => _execFunc(this) );
    }

    public object Execute()
    {
        return _execFunc(this);
    }

    public bool TryExecute(out object result)
    {
        try
        {
            result = _execFunc(this);
            return true;
        }
        catch(Exception ex)
        {
            result = null;
            return false;
        }
    }

    public Command (Func<ICommand, object> execFunc)
    {
        if (execFunc == null) throw new ArgumentNullException("execFunc");
        _execFunc = execFunc;
    }
}

namespace Generic
{
    public class Command<TResult> : Command, ICommand<TResult> where TResult : class            
    {
        new protected Func<ICommand<TResult>, TResult> ExecFunc => (ICommand<TResult> cmd) => (TResult)base.ExecFunc(cmd);

        public bool TryExecute(out TResult result)
        {
            try
            {
                result = ExecFunc(this);
                return true;
            }
            catch(Exception ex)
            {
                result = null;
                return false;
            }
        }

        Task<TResult> ICommand<TResult>.BeginExecute()
        {
            return Task<TResult>.Factory.StartNew(() => ExecFunc(this) );
        }

        TResult ICommand<TResult>.Execute()
        {
            return ExecFunc(this);
        }

        public Command(Func<ICommand<TResult>, TResult> execFunc) : base((ICommand c) => (object)execFunc((ICommand<TResult>)c))
        {
        }
    }
}

public class ConcatCommand : Generic.Command<string> 
{
    private IEnumerable<string> _inputs;
    public IEnumerable<String> Inputs => _inputs;

    public ConcatCommand(IEnumerable<String> inputs) : base( (Generic.ICommand<string> c) => (string)String.Concat(((ConcatCommand)c).Inputs) )
    {
        if (inputs == null) throw new ArgumentNullException("inputs");
        _inputs = inputs;
    }

}

class Program
{
    static void Main(string[] args)
    {
        string[] inputs = { "This", " is ", " a ", " very ", " fine ", " wine!" };
        ICommand c = new ConcatCommand(inputs );
        string results = (string)c.Execute();
        Console.WriteLine(results);
        Console.ReadLine();
    }
}
公共接口ICommand
{
对象执行();
布尔TryExecute(输出对象结果);
任务开始执行();
}
命名空间泛型
{
公共接口ICommand:ICommand
{
新的TResult Execute();
布尔TryExecute(输出结果);
新任务开始执行();
}
}
公共类命令:ICommand
{
private Func _execFunc=null;
受保护的Func ExecFunc{get{return\u ExecFunc;}}
公共任务开始执行()
{
返回Task.Factory.StartNew(()=>\u execFunc(this));
}
公共对象执行()
{
返回_execFunc(本);
}
公共布尔TryExecute(输出对象结果)
{
尝试
{
结果=_execFunc(此);
返回true;
}
捕获(例外情况除外)
{
结果=空;
返回false;
}
}
公共命令(Func execFunc)
{
如果(execFunc==null)抛出新的ArgumentNullException(“execFunc”);
_execFunc=execFunc;
}
}
命名空间泛型
{
公共类命令:Command,ICommand,其中TResult:class
{
新的受保护Func ExecFunc=>(ICommand cmd)=>(TResult)base.ExecFunc(cmd);
公共bool TryExecute(输出结果)
{
尝试
{
结果=ExecFunc(此);
返回true;
}
捕获(例外情况除外)
{
结果=空;
返回false;
}
}
任务ICommand.BeginExecute()
{
返回Task.Factory.StartNew(()=>ExecFunc(this));
}
TResult ICommand.Execute()
{
返回ExecFunc(本);
}
公共命令(Func execFunc):base((ICommand c)=>(object)execFunc((ICommand)c))
{
}
}
}
公共类ConcatCommand:Generic.Command
{
私有IEnumerable_输入;
公共IEnumerable输入=>\u输入;
公共ConcatCommand(IEnumerable输入):base((Generic.ICommand c)=>(string)string.Concat(((ConcatCommand)c.inputs))
{
如果(inputs==null)抛出新的ArgumentNullException(“inputs”);
_输入=输入;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
字符串[]输入={“This”、“is”、“a”、“very”,