我正在尝试为我的数据结构实现访问者模式,它基于类层次结构。 在 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/