2015-09-19 74 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);