【问题标题】:How do I simulate anonymous classes in C#如何在 C# 中模拟匿名类
【发布时间】:2010-01-15 20:00:48
【问题描述】:

我正在用 C# 编写一个小型数据结构库,但遇到了架构问题。本质上我有一个实现访问者模式的类,访问者有很多可能的实现:

public interface ITreeVisitor<T, U>
{
    U Visit(Nil<T> s);
    U Visit(Node<T> s);
}

public abstract class Tree<T> : IEnumerable<T>
{
    public readonly static Tree<T> empty = new Nil<T>();
    public abstract U Accept<U>(ITreeVisitor<T, U> visitor);
}

public sealed class Nil<T> : Tree<T>
{
    public override U Accept<U>(ITreeVisitor<T, U> visitor) { return visitor.Visit(this); }
}

public sealed class Node<T> : Tree<T>
{
    public Tree<T> Left { get; set; }
    public T Value { get; set; }
    public Tree<T> Right { get; set; }

    public override U Accept<U>(ITreeVisitor<T, U> visitor) { return visitor.Visit(this); }
}

任何时候我想传入一个访问者,我必须创建一个访问者类,实现接口,然后像这样传入:

class InsertVisitor<T> : ITreeVisitor<T, Tree<T>> where T : IComparable<T>
{
    public T v { get; set; };

    public Tree<T> Visit(Nil<T> s)
    {
        return new Node<T>() { Left = Tree<T>.empty, Value = v, Right = Tree<T>.empty };
    }

    public Tree<T> Visit(Node<T> s)
    {
        switch (v.CompareTo(s.Value))
        {
            case -1: return new Node<T>() { Left = Insert(v, s.Left), Value = s.Value, Right = s.Right };
            case 1: return new Node<T>() { Left = s.Left, Value = s.Value, Right = Insert(v, s.Right) };
            default: return s;
        }
    }
}

public static Tree<T> Insert<T>(T value, Tree<T> tree) where T : IComparable<T>
{
    return tree.Accept<Tree<T>>(new InsertVisitor<T>() { v = value });
}

我不喜欢写那么多样板代码,因为当你有大量的访问者实现时,它会变得非常混乱。

想写类似anonymous classes Java的东西(概念代码):

public static Tree<T> Insert<T>(T v, Tree<T> tree) where T : IComparable<T>
{
    return tree.Accept<Tree<T>>(new InsertVisitor<T>()
        {
            public Tree<T> Visit(Nil<T> s) { return new Node<T>() { Left = Tree<T>.empty, Value = v, Right = Tree<T>.empty }; }
            public Tree<T> Visit(Node<T> s)
            {
                switch (v.CompareTo(s.Value))
                {
                    case -1: return new Node<T>() { Left = Insert(v, s.Left), Value = s.Value, Right = s.Right };
                    case 1: return new Node<T>() { Left = s.Left, Value = s.Value, Right = Insert(v, s.Right) };
                    default: return s;
                 }
            }
        };
}

有没有办法在 C# 中模拟带有接口实现的匿名类?

【问题讨论】:

  • 可能想解释一下什么是匿名接口。恐怕我不知道这意味着什么。
  • @Noldorin: 匿名 interface 不是最好的词选择,我的意思是匿名 class。 Java 中有一个特性,您可以在不需要命名类的情况下即时实现接口——我想在 C# 中做类似的事情。
  • 你确定不能和代表们凑合?
  • 在 C# 中,匿名类型不能实现接口。请参阅此处了解更多信息:msdn.microsoft.com/en-us/library/bb397696%28VS.100%29.aspx
  • 我不确定我是否做对了,但是你能用通用逻辑创建一个访问者基类,而不是访问者界面吗?

标签: c# design-patterns anonymous-class


【解决方案1】:

您可以将类的“行为”部分从针对接口定义的方法更改为在适当时间调用的委托,并通过传递新委托来创建新访问者——从而征用匿名函数来完成匿名类的工作.

草图代码(未测试,可酌情清理):

class CustomVisitor<T> : ITreeVisitor<T, Tree<T>> where T : IComparable<T>
{
    public T v { get; set; };
    public Func<Nil<T>,  Tree<T>> VisitNil  { get; set; }
    public Func<Node<T>, Tree<T>> VisitNode { get; set; }

    public Tree<T> Visit(Nil<T>  s) { return VisitNil(s);  }
    public Tree<T> Visit(Node<T> s) { return VisitNode(s); }
}

public static Tree<T> Insert<T>(T v, Tree<T> tree) where T : IComparable<T>
{
    return tree.Accept<Tree<T>>(new CustomVisitor<T> {
        VisitNil  = s =>
            return new Node<T>() { Left = Tree<T>.empty, Value = v, Right = Tree<T>.empty }; }
        VisitNode = s =>
        {
            switch (v.CompareTo(s.Value))
            {
                case -1: return new Node<T>() { Left = Insert(v, s.Left), Value = s.Value, Right = s.Right };
                case  1: return new Node<T>() { Left = s.Left, Value = s.Value, Right = Insert(v, s.Right) };
                default: return s;
             }
        }
    });
}

【讨论】:

  • +1, +answer: 哦,哇,这比我想象的要简单 :) 我担心需要使用 if (tree is Nil) { ... } else { ... } 重写我的代码只是为了保留所有的树遍历逻辑用同样的方法。非常感谢!
  • 这是一个很好的例子,说明函数式编程概念如何为面向对象的语言增加价值。 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多