2010-01-15 11 views
10

में अज्ञात वर्गों का अनुकरण कैसे करूं मैं सी # में एक छोटी डेटा संरचना लाइब्रेरी लिख रहा हूं, और मैं एक वास्तुशिल्प समस्या में भाग रहा हूं। अनिवार्य रूप से मैं एक वर्ग है जो आगंतुक पैटर्न को लागू करता है, और आगंतुकों के कई संभावित कार्यान्वयन हैं:मैं सी #

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

वहाँ किसी भी तरह से सी # में इंटरफ़ेस कार्यान्वयन के साथ गुमनाम वर्गों अनुकरण करने के लिए है?

+2

व्याख्या करने के लिए क्या एक गुमनाम इंटरफेस है सकते हैं। मुझे डर है कि मेरे पास इसका कोई मतलब नहीं है। – Noldorin

+2

@Noldorin: अज्ञात * इंटरफ़ेस * शब्दों का सबसे अच्छा विकल्प नहीं है, मेरा मतलब अज्ञात * वर्ग * था। जावा में एक सुविधा है जहां आप नामित कक्षा की आवश्यकता के बिना फ्लाई पर इंटरफेस को कार्यान्वित कर सकते हैं - मैं सी # में कुछ ऐसा करना चाहता हूं। – Juliet

+0

क्या आप वाकई प्रतिनिधियों के साथ नहीं कर सकते हैं? –

उत्तर

7

आप उचित समय पर बुलाए गए प्रतिनिधियों को एक इंटरफ़ेस के खिलाफ परिभाषित विधियों से कक्षा के "व्यवहार" भाग को बदल सकते हैं, और नए प्रतिनिधियों को पारित करके एक नया आगंतुक बना सकते हैं - जिससे काम करने के लिए अज्ञात कार्यों को शामिल किया जा सकता है अनाम कक्षाएं

स्केच कोड (परीक्षण किया है, आप के रूप में उपयुक्त साफ कर सकते हैं नहीं):

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

+1, + उत्तर: ओह वाह, यह मैंने सोचा जितना आसान था :) मुझे चिंता थी कि 'अगर (पेड़' का उपयोग करके मेरा कोड दोबारा लिखना होगा नील) {...} अन्य {...} 'बस एक ही विधि में निहित सभी पेड़ ट्रैवर्सल तर्क रखने के लिए। बहुत सराहना की! – Juliet

+1

यह एक अच्छा उदाहरण है कि कैसे कार्यात्मक प्रोग्रामिंग अवधारणा ऑब्जेक्ट उन्मुख भाषाओं में मूल्य जोड़ सकती है। =) –