具有多态性的 C# Func<Interface>

标签 c# visitor-pattern dynamic-dispatch

我正在尝试为我的数据结构实现访问者模式,它基于类层次结构。 在 C# 中,您无法打开类型(目前)。我正在考虑做这样的事情作为替代:

public MyAlgorithm : Func<IBase, X> {
    // default:
    public X apply(IBase data) {}

    // case param1 is ConcreteSubclass
    public X apply(ConcreteSubclass data) {}

    // case param1 is ConcreteOtherClass
    public X apply(ConcreteOtherClass data) {}
}

然后用后期绑定(bind)调度调用它:

public ICanApplyAlgorithmOn {
    public void apply(Func<IBase> alg);
    public TResult apply<TResult>(Func<IBase,TResult> alg);
    public TResult apply<TParam1,TResult>(Func<IBase, TParam1, TResult> alg);
    // etc.
}

public abstract Base : ICanApplyAlgorithmOn {
    // etc.
    public TResult apply(Func<IBase, X> alg) {
        // Hopefully I am correct in deducing that this will call the various apply(...) implementations instead of always method(IBase)
        dynamic me = this;
        return alg(me);
    }
    // etc.
}

但是,这行不通,因为 MyAlgorithm无法从委托(delegate)继承 Func<...> .

我看到的唯一解决方案是定义很多我自己的接口(interface),如下所示。有没有更好的办法?

public interface IAlgorithm { public void apply(IBase data); }
public interface IAlgorithm<TReturn> { public TReturn apply(IBase data); }
public interface IAlgorithm<TP1, TReturn> { public TReturn apply(IBase data, TP1 param1); }
// etc.

最佳答案

  • 访客模式是一种手动实现双重调度的方式。
  • 使用 dynamic 启用多重分派(dispatch)。

如果您的目标只是根据参数的运行时类型选择一个函数,那么选择这两个选项中的一个就足够了——没有必要将它们结合起来。

这是一个使用 dynamic 而不是访问者的解决方案:

class MyAlgorithm
{
    public X Apply(IBase data)
    {
        try
        {
            return ApplyImpl((dynamic) data);
        }
        catch (RuntimeBinderException ex)
        {
            throw new ArgumentException(
                string.Format("{0} is not implemented for type {1}.", typeof (MyAlgorithm).Name, data.GetType().Name),
                ex);
        }
    }

    private X ApplyImpl(ConcreteSubclass sub)
    {
        // Your implementation here.
        return null;
    }

    private X ApplyImpl(ConcreteOtherClass sub)
    {
        // Your implementation here.
        return null;
    }
}

你可以这样使用它:

var algorithm = new MyAlgorithm();
var data = new ConcreteSubclass();
algorithm.Apply(data);

或者,您可以像这样使用委托(delegate):

Func<IBase, X> func = algorithm.Apply;
func(data);

关于具有多态性的 C# Func<Interface>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32849466/

相关文章:

c++ - 如何在派生类中访问聚合

java - 相关类(class)的多名访客

c++ - 究竟为什么编译器直到运行时才能确定变量的真实类型?

c# - 检查 .NET 中的目录和文件写入权限

c# - 在 ASP.NET 中将 UNC 路径转换为 ​​ 'file:///' URL

访问者在子类节点上的 C++ 访问者模式丢失 "is a"关系

rust - “associated type … must be specified”,但未使用

c# - 如何通过参数化查询在数据库中插入空值

c# - 如何强制 SqlCommand 不将参数编码为 un​​icode/nvarchar?