我在Composite C#中实现自定义比较器时遇到问题。我想传递自定义比较器我的Composite对象。
这是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; }
}
}
对于Component,Composite对象我使用相同的接口。
复合(我的组件集合)
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));
}
}
}
你能帮我实现自定义比较器并传递给Find方法吗? 是不是好方法?
非常感谢
答案 0 :(得分:0)
这里的主要问题是:
Name
属性T
Find
方法获取类型为T
的通用项目以进行查找和比较
它带有组件名称 - 这只适用于IComponent<string>
因此,最简单的(也是我首选的)解决方案是摆脱比较器。 相反,我会用谓词定义find方法(如评论中所述)。
但你要求比较器!
因此需要进行一些调整:
在T Data {get; set;}
中定义属性IComponent<T>
在Component<T>
和Composite<T>
如果您愿意,可以从IComparer<T>
切换到IEqualityComparer<IComponent<T>>
因为你想搜索相等的组件而不是比较元素
相应地更改删除方法
在代码中(缩短一点):
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);