c# - 在 C# 中实现模式匹配

标签 c# pattern-matching

在 Scala 中,您可以使用模式匹配来根据输入的类型生成结果。例如:

val title = content match {
    case blogPost: BlogPost => blogPost.blog.title + ": " + blogPost.title
    case blog: Blog => blog.title
}

在 C# 中,我希望能够编写:

var title = Visit(content,
    (BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title,
    (Blog blog) => blog.Title
);

这可能吗?当我尝试将其作为单一方法编写时,我不知道如何指定泛型。以下实现似乎是正确的,除了让类型检查器允许函数接受 T 的子类型:

    public TResult Visit<T, TResult>(T value, params Func<T, TResult>[] visitors)
    {
        foreach (var visitor in visitors)
        {
            if (visitor.Method.GetGenericArguments()[0].IsAssignableFrom(value.GetType()))
            {
                return visitor(value);
            }
        }
        throw new ApplicationException("No match");
    }

我得到的最接近的方法是将函数单独添加到一个对象,然后调用一个值的访问:

    public class Visitor<T, TResult>
    {
        private class Result
        {
            public bool HasResult;
            public TResult ResultValue;
        }

        private readonly IList<Func<T, Result>> m_Visitors = new List<Func<T, Result>>();

        public TResult Visit(T value)
        {
            foreach (var visitor in m_Visitors)
            {
                var result = visitor(value);
                if (result.HasResult)
                {
                    return result.ResultValue;
                }
            }
            throw new ApplicationException("No match");
        }

        public Visitor<T, TResult> Add<TIn>(Func<TIn, TResult> visitor) where TIn : T
        {
            m_Visitors.Add(value =>
            {
                if (value is TIn)
                {
                    return new Result { HasResult = true, ResultValue = visitor((TIn)value) };
                }
                return new Result { HasResult = false };
            });
            return this;
        }
    }

可以这样使用:

var title = new Visitor<IContent, string>()
    .Add((BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title)
    .Add((Blog blog) => blog.Title)
    .Visit(content);

知道如何通过单个方法调用来做到这一点吗?

最佳答案

模式匹配是 F# 等函数式编程语言中常见的可爱功能之一。 codeplex 中正在进行一个名为 Functional C# 的伟大项目. 考虑以下 F# 代码:

let operator x = match x with
                 | ExpressionType.Add -> "+"

let rec toString exp = match exp with
                       | LambdaExpression(args, body) -> toString(body)
                       | ParameterExpression(name) -> name
                       | BinaryExpression(op,l,r) -> sprintf "%s %s %s" (toString l) (operator op) (toString r)

使用 Functional C# 库,C# 等效项为:

var Op = new Dictionary<ExpressionType, string> { { ExpressionType.Add, "+" } };

Expression<Func<int,int,int>> add = (x,y) => x + y;

Func<Expression, string> toString = null;
 toString = exp =>
 exp.Match()
    .With<LambdaExpression>(l => toString(l.Body))
    .With<ParameterExpression>(p => p.Name)
    .With<BinaryExpression>(b => String.Format("{0} {1} {2}", toString(b.Left), Op[b.NodeType], toString(b.Right)))
    .Return<string>();

关于c# - 在 C# 中实现模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6031555/

相关文章:

jquery - 在字符串中的任何位置找到模式?

c# - XmlDocument 忽略 xmlns

c# - 使用 SlimDX 绘制 2D

c# - 5.0 之前的 c# 中的异步编程没有 async & await?

c# - µ 和 é 在命名空间中

c# - OVER 子句中的 SQL ORDER BY 与 CLR 聚合不兼容?

python - 用星号python分割字符串

Scala - 复杂条件模式匹配

arrays - 二维数组连续元素算法

java - Java正则表达式中的空格