代码之家  ›  专栏  ›  技术社区  ›  Juliet

如何在C中模拟匿名类#

  •  10
  • Juliet  · 技术社区  · 15 年前

    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#中的接口实现来模拟匿名类?

    1 回复  |  直到 15 年前
        1
  •  7
  •   mqp    15 年前

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

    草图代码(未测试,您可以根据需要进行清理):

    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;
                 }
            }
        });
    }