2015-09-19 80 views
0

我在複合C#中實現自定義比較器有問題。我想傳遞自定義比較器我的複合對象。與自定義比較器複合

這裏是IComponent的接口:

namespace composite 
{ 
    public interface IComponent<T> 
    { 
     void Add(IComponent<T> component); 
     IComponent<T> Find(T item); 
     IComponent<T> Remove(T item); 
     string Display(int depth); 
     string Name { get; set; } 
    } 
} 

對於組件使用相同的接口一個複合對象I'm。

複合(我的組件的集合)

namespace composite 
{ 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Runtime.CompilerServices; 
    using System.Text; 

    public class Composite<T> : IComponent<T> 
    { 
     private ICollection<IComponent<T>> components;  
     private IComponent<T> holder; 

     public Composite(string name) 
     { 
      this.Name = name; 
      this.holder = null; 
      this.components = new List<IComponent<T>>(); 
     } 

     public string Name { get; set; } 

     public void Add(IComponent<T> component) 
     { 
      this.components.Add(component); 
     } 

     public IComponent<T> Find(T item) 
     { 
      this.holder = this; 
      if (item.Equals(this.Name)) 
      { 
       return this; 
      } 

      IComponent<T> found = null; 

      //this.components.Select(s => s.Name == item) 

      foreach (IComponent<T> component in this.components) 
      { 
       found = component.Find(item); 
       if (found != null) 
       { 
        break; 
       } 
      } 
      return found; 
     } 

     public IComponent<T> Remove(T item) 
     { 
      this.holder = this; 
      IComponent<T> p = holder.Find(item); 
      if (this.holder != null) 
      { 
       (this.holder as Composite<T>).components.Remove(p); 
       return this.holder; 
      } 
      else 
      { 
       return this; 
      } 
     } 

     //public IEnumerable<IComponent<T>> Dsiplay(int depth)  

     public string Display(int depth) 
     { 
      StringBuilder s = new StringBuilder(); 
      s.Append("set " + this.Name + " length :" + this.components.Count + "\n"); 
      foreach (IComponent<T> component in components) 
      { 
       s.Append(component.Display(depth + 2)); 
      } 
      return s.ToString(); 
     } 
    } 
} 

組件:

namespace composite 
{ 
    using System; 
    using System.Collections.Generic; 

    public class Component<T> : IComponent<T> 
    { 
     public Component(string name) 
     { 
      this.Name = name; 
     } 

     public string Display(int depth) 
     { 
      return new string('-', depth) + this.Name + "\n"; 
     } 

     public string Name { get; set; } 

     public IComparer<T> MyComparer { get; private set; } 

     //public IComparer<T> myComparer { set; } 

     public void Add(IComponent<T> item) 
     { 
      throw new NotImplementedException(); 
     } 

     public IComponent<T> Find(T item) 
     { 

      //Here I want to use comparer object, instead of Equals 
      //Something like this: 

      //return MyComparer.Compare(...) == 0 ? this : null; 

      return item.Equals(this.Name) ? this : null; 
     } 

     public IComponent<T> Remove(T item) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

最後我的主要功能:

namespace composite 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //Creating custom comparer and pass to the constructor composite? 
      IComparer<string> myComparer = new ... 


      IComponent<string> comp1 = new Component<string>("Komponenta 1"); 
      IComponent<string> comp2 = new Component<string>("Komponenta 2"); 
      IComponent<string> comp3 = new Component<string>("Komponenta 3"); 
      IComponent<string> comp4 = new Component<string>("Komponenta 4"); 
      IComponent<string> comp5 = new Component<string>("Komponenta 5"); 

      IComponent<string> composite = new Composite<string>("Composite 1"); 

      IComponent<string> composite2 = new Composite<string>("Composite 2"); 

      composite.Add(comp1); 
      composite.Add(comp2); 
      composite.Add(comp3); 
      composite.Add(comp4); 
      composite.Add(comp5); 

      composite2.Add(comp1); 
      composite2.Add(comp2); 
      composite2.Add(comp3); 
      composite2.Add(comp4); 
      composite2.Add(comp5); 

      composite.Add(composite2); 

      Console.Write(composite.Display(0)); 
     } 
    } 
} 

你能幫助我imple自定義比較器並傳遞給Find方法? 是不是好方法?

非常感謝

+0

什麼問題?向'find'方法'IEqualityComparer 比較器'或像許多LINQ方法'Func 謂詞'中添加第二個參數並在其中使用它。作爲一個側面說明,'holder'字段和'Composite.Find/Remove'的當前實現非常奇怪。 –

+0

你也可以在T上添加一個IComparable約束,就像'public interface IComponent where T:IComparable' – venerik

+0

謝謝你的回答。是的,我知道,但問題是,如何實現這個比較器。因爲,我想通過** string Name **比較,但比較器**有一個T型**,所以比較方法也會有T輸入類型。我不能實現T類型的object.Name。這是什麼,我不明白。謝謝 –

回答

0

這裏的主要問題是:

  • 組件有一個Name財產
  • 的組件不使用泛型類型參數T
  • Find方法獲取一個類型爲T的通用物品,用於查找並比較 它與組件名稱 - 這僅適用於IComponent<string>

所以最簡單的(和我的首選)解決方案將擺脫比較。 相反,我會用謂詞定義find方法(如註釋中所述)。

但你問了一個比較器!

所以有一些調整,以使:

  • IComponent<T>定義屬性T Data {get; set;}和 在Component<T>如果你想提供一個實現從IComparer<T>IEqualityComparer<IComponent<T>>Composite<T>

  • 開關 ,因爲您想要搜索相同的組件而不是比較元素

  • 變化remove方法相應

在代碼(縮短少許):

public interface IComponent<T> 
{ 
    void Add(IComponent<T> component); 
    IComponent<T> Find(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer); 
    IComponent<T> Find(Predicate<IComponent<T>> condition) 
    bool Remove(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer); 
    string Display(int depth); 
    string Name { get; set; } 
    T Data { get; set; } 
} 

public class Component<T> : IComponent<T> 
{ 

    public T Data { get; set; } 
    public string Name { get; set; } 

    public Component(string name) 
     => Name = name; 

    public string Display(int depth) => 
     new string('-', depth) + Name + "\n"; 

    public IComponent<T> Find(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer) 
     => comparer.Equals(item, this) ? this : null; 

    public IComponent<T> Find(Predicate<IComponent<T>> condition) 
     => condition(this) ? this : null; 

    public void Add(IComponent<T> item) 
     => throw new InvalidOperationException(); 

    public bool Remove(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer) 
     => throw new InvalidOperationException(); 

}  

public class Composite<T> : IComponent<T> 
{ 
    private IList<IComponent<T>> components = new List<IComponent<T>>(); 
    public T Data { get; set; } 
    public string Name { get; set; } 

    public Composite(string name) 
     => Name = name; 

    public void Add(IComponent<T> component) 
     => components.Add(component); 

    public IComponent<T> Find(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer) 
    { 
     if (comparer.Equals(item, this)) 
      return this; 
     else 
      foreach (var component in components) 
      { 
       var childItem = component.Find(item, comparer); 
       if (childItem != null) 
        return childItem; 
      } 
     return null; 
    } 

    public bool Remove(IComponent<T> item, IEqualityComparer<IComponent<T>> comparer) 
    { 
     var result = false; 
     for (var i = components.Count - 1; i >= 0; i--) 
      if (comparer.Equals(components[i], item)) 
      { 
       components.RemoveAt(i); 
       result = true; 
      } 

     return result; 
    } 

    public IComponent<T> Find(Predicate<IComponent<T>> condition) 
    { 
     if (condition(this)) 
      return this; 
     foreach (var item in components) 
     { 
      var result = item.Find(condition); 
      if (result != null) 
       return result; 
     } 
     return null; 
    } 

    public string Display(int depth) 
    { 
     var s = new StringBuilder(); 
     s.Append(new string('-', depth) + "set " + Name + " length :" + components.Count + "\n"); 
     foreach (var component in components) 
      s.Append(component.Display(depth + 2)); 
     return s.ToString(); 
    } 
} 

兩個比較器的實現將是:

public class DefaultComparer<T> : IEqualityComparer<IComponent<T>> 
{ 

    public bool Equals(IComponent<T> x, IComponent<T> y) 
     => EqualityComparer<T>.Default.Equals(x.Data, y.Data); 

    public int GetHashCode(IComponent<T> obj) 
     => EqualityComparer<T>.Default.GetHashCode(obj.Data); 

} 

public class NameComparer<T> : IEqualityComparer<IComponent<T>> 
{ 
    public bool Equals(IComponent<T> x, IComponent<T> y) 
     => string.Equals(x.Name, y.Name); 

    public int GetHashCode(IComponent<T> obj) 
     => (obj.Name ?? string.Empty).GetHashCode(); 
} 

如何使用該?

如果你想給定的名稱來搜索組件,您現在可以使用:

 var element1 = composite.Find(new Component<string>("Komponenta 5"), new NameComparer<string>()); 
     Console.WriteLine(element1.Name); 

或者更簡單的方法:

 var element2 = composite.Find(t => string.Equals(t.Name, "Komponenta 5")); 
     Console.WriteLine(element2.Name);