C#Func<;界面>;多态性

C#Func<;界面>;多态性,c#,visitor,dynamic-dispatch,C#,Visitor,Dynamic Dispatch,我试图为我的数据结构实现访问者模式,它基于类层次结构。 在C#中,还不能打开类型。我正在考虑做这样的事情作为替代: public MyAlgorithm : Func<IBase, X> { // default: public X apply(IBase data) {} // case param1 is ConcreteSubclass public X apply(ConcreteSubclass data) {} // case

我试图为我的数据结构实现访问者模式,它基于类层次结构。 在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) {}
}
  • 访问者模式是一种手动实现双重分派的方法
  • 使用
    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);
Func<IBase, X> func = algorithm.Apply;
func(data);
public X Accept(IAlgorithmVisitor<X> visitor)
{
    return visitor.Visit(this);
}
此外,您也可以使用如下委托:

var algorithm = new MyAlgorithm();
var data = new ConcreteSubclass();
algorithm.Apply(data);
Func<IBase, X> func = algorithm.Apply;
func(data);
public X Accept(IAlgorithmVisitor<X> visitor)
{
    return visitor.Visit(this);
}
Func=algorithm.Apply;
func(数据);
  • 访问者模式是一种手动实现双重分派的方法
  • 使用
    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);
Func<IBase, X> func = algorithm.Apply;
func(data);
public X Accept(IAlgorithmVisitor<X> visitor)
{
    return visitor.Visit(this);
}
此外,您也可以使用如下委托:

var algorithm = new MyAlgorithm();
var data = new ConcreteSubclass();
algorithm.Apply(data);
Func<IBase, X> func = algorithm.Apply;
func(data);
public X Accept(IAlgorithmVisitor<X> visitor)
{
    return visitor.Visit(this);
}
Func=algorithm.Apply;
func(数据);

您需要两个接口。一个用于访问者,一个用于可访问类

public interface IAlgorithmVisitor<X>
{
    public X Visit(IBase data);
    public X Visit(ConcreteSubclass data);
    public X Visit(ConcreteOtherClass data);
}

public interface IAlgorithmVisitable<X>
{
    X Accept(IAlgorithmVisitor<X> visitor);
}
注意,方法重载机制根据当前类型自动调用
Visit
的右重载。正确的方法重载在编译时解决!(不需要动态延迟绑定。)


现在,您可以迭代一组类似这样的算法

IAlgorithmVisitor<int> visitor = new ConcreteAlgorithmVisitor<int>();
foreach (var algorithm in intAlgorithms) {
    int result = algorithm.Accept(visitor);
    //TODO: do something with result.
}
IAlgorithmVisitor visitor=new-ConcreteAlgorithmVisitor();
foreach(intAlgorithms中的var算法){
int result=algorithm.Accept(访问者);
//TODO:做一些有结果的事情。
}
但是,从
Accept
Visit
方法返回结果是不常见的,因为访问者的任务是做一些有用的事情。它不是迭代器或接受对象的任务。这使您能够创建执行完全不同的操作的访问者


也许与。相比,更适合您的需要。

您需要两个接口。一个用于访问者,一个用于可访问类

public interface IAlgorithmVisitor<X>
{
    public X Visit(IBase data);
    public X Visit(ConcreteSubclass data);
    public X Visit(ConcreteOtherClass data);
}

public interface IAlgorithmVisitable<X>
{
    X Accept(IAlgorithmVisitor<X> visitor);
}
注意,方法重载机制根据当前类型自动调用
Visit
的右重载。正确的方法重载在编译时解决!(不需要动态延迟绑定。)


现在,您可以迭代一组类似这样的算法

IAlgorithmVisitor<int> visitor = new ConcreteAlgorithmVisitor<int>();
foreach (var algorithm in intAlgorithms) {
    int result = algorithm.Accept(visitor);
    //TODO: do something with result.
}
IAlgorithmVisitor visitor=new-ConcreteAlgorithmVisitor();
foreach(intAlgorithms中的var算法){
int result=algorithm.Accept(访问者);
//TODO:做一些有结果的事情。
}
但是,从
Accept
Visit
方法返回结果是不常见的,因为访问者的任务是做一些有用的事情。它不是迭代器或接受对象的任务。这使您能够创建执行完全不同的操作的访问者


也许比更适合您的需要。

我不太清楚您要归档什么,但对于快速运行时类型绑定,您可以使用以下代码:

您可以使用
字典
,如下所示:

public class AlgorithmClass<TReturn>
{
    private Dictionary<Type, Func<object, TReturn>> mMethods;

    public AlgorithmClass<TReturn>(Dictionary<Type, Func<object, TReturn>> methods)
    {
        mMethods = methods
    }

    public TReturn Invoke(object argument)
    {
        Type type = argument.GetType();

        //This line supports inheritance and co/contra-variance.
        //If you want to archive full performance and not support those features you can just use mMethods.TryGetValue(type, out Func<object, TReturn>);
        var kvps = mMethods.Where(x => x.Key.IsAssignableFrom(type));

        if(!kvp.Any())
        {
            throw new MissingMethodException("There is no method which can take " + type.Name + " as an argument");
        }

        if(kvp.Count() > 1)
        {
            throw new ArgumentException("There is more than one method which can take " + type.Name + " as an argument");
        }

        return kvp.First().Value(argument);
    }
}
公共类算法类
{
私人字典方法;
公共算法类(字典方法)
{
方法=方法
}
公共TReturn调用(对象参数)
{
Type Type=argument.GetType();
//该行支持继承和协方差/反方差。
//如果您想归档全部性能而不支持这些功能,您可以使用mMethods.TryGetValue(type,out Func);
var kvps=mMethods.Where(x=>x.Key.IsAssignableFrom(type));
如果(!kvp.Any())
{
抛出new MissingMethodException(“没有可以将“+type.Name+”作为参数的方法”);
}
如果(kvp.Count()>1)
{
抛出新ArgumentException(“有多个方法可以将“+type.Name+”作为参数”);
}
返回kvp.First().Value(参数);
}
}
现在,您可以在代码中使用如下类:

AlgorithmClass<ReturnType> algorithm = new AlgorithmClass(new Dictionary<Type, Func<object, ReturnType>>
    {
        {typeof(int), MethodForIntType},
        {typeof(string), MethodForStringType},
        {typeof(MyClass), MethodForMyClassType}
    });

ReturnType MethodForIntType(object anInt)
{
    code...
}

ReturnType MethodForStringType(object aString)
{
    code...
}

ReturnType MethodForMyClassType(object aMyClass)
{
    code...
}
AlgorithmClass算法=新算法类(新字典
{
{typeof(int),MethodForIntType},
{typeof(string),MethodForStringType},
{typeof(MyClass),MethodForMyClassType}
});
ReturnType MethodForIntType(对象anInt)
{
代码。。。
}
ReturnType MethodForStringType(对象搜索)
{
代码。。。
}
ReturnType MethodForMyClassType(对象类)
{
代码。。。
}

在运行时使用
dynamic
System.Reflection
的方法
Binder
会降低程序的速度(尽管将
对象
用作参数需要在方法开始时进行装箱取消装箱强制转换).

我不太清楚您试图归档的内容,但对于快速运行时类型绑定,您可以使用以下代码:

您可以使用
字典
,如下所示:

public class AlgorithmClass<TReturn>
{
    private Dictionary<Type, Func<object, TReturn>> mMethods;

    public AlgorithmClass<TReturn>(Dictionary<Type, Func<object, TReturn>> methods)
    {
        mMethods = methods
    }

    public TReturn Invoke(object argument)
    {
        Type type = argument.GetType();

        //This line supports inheritance and co/contra-variance.
        //If you want to archive full performance and not support those features you can just use mMethods.TryGetValue(type, out Func<object, TReturn>);
        var kvps = mMethods.Where(x => x.Key.IsAssignableFrom(type));

        if(!kvp.Any())
        {
            throw new MissingMethodException("There is no method which can take " + type.Name + " as an argument");
        }

        if(kvp.Count() > 1)
        {
            throw new ArgumentException("There is more than one method which can take " + type.Name + " as an argument");
        }

        return kvp.First().Value(argument);
    }
}
公共类算法类
{
私人字典方法;
公共算法类(字典方法)
{
方法=方法
}
公共TReturn调用(对象参数)
{
Type Type=argument.GetType();
//该行支持继承和协方差/反方差。
//如果您想归档全部性能而不支持这些功能,您可以使用mMethods.TryGetValue(type,out Func);
var kvps=mMethods.Where(x=>x.Key.IsAssignableFrom(type));
如果(!kvp.Any())
{
抛出new MissingMethodException(“没有可以接受“+type.Name+”的方法”