C# · 12月 31, 2021

如何在C#中模拟匿名类

我在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,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,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,Right = s.Right }; case 1: return new Node<T>() { Left = s.Left,s.Right) }; default: return s; } } };}

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

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

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

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,Right = Tree<T>.empty }; } VisitNode = s => { switch (v.CompareTo(s.Value)) { case -1: return new Node<T>() { Left = Insert(v,Right = s.Right }; case 1: return new Node<T>() { Left = s.Left,s.Right) }; default: return s; } } });}