簡體   English   中英

與自定義比較器組合

[英]Composite with custom comparer

我在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方法嗎? 這是好方法嗎?

很感謝

這里的主要問題是:

  • 組件具有Name屬性
  • 組件不使用通用類型參數T
  • Find方法獲取類型為T的通用項以查找並將其與組件名稱進行比較-這僅適用於IComponent<string>

因此,最簡單(也是我的首選)解決方案是擺脫比較器。 相反,我將定義一個帶謂詞的find方法(如注釋中所述)。

但是你要一個比較器!

因此,需要進行一些調整:

  • 定義屬性T Data {get; set;} 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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM