program story

객체의 필드를 일반 사전 키로 사용

inputbox 2020. 7. 27. 07:55
반응형

객체의 필드를 일반 사전 키로 사용


객체를의 키로 사용하려면 Dictionary특정 방식으로 객체를 비교하기 위해 어떤 방법을 재정의해야합니까?

속성이있는 클래스가 있다고 가정 해보십시오.

class Foo {
    public string Name { get; set; }
    public int FooID { get; set; }

    // elided
} 

그리고 나는 :

Dictionary<Foo, List<Stuff>>

Foo같은 개체를 FooID같은 그룹으로 간주하고 싶습니다 . Foo클래스 에서 어떤 메서드를 재정의해야 합니까?

요약하면 : Stuff객체를 Foo객체 별로 그룹화하여 목록 으로 분류하려고 합니다. Stuff객체는 FooID카테고리에 링크 할 수 있습니다.


기본적으로 두 가지 중요한 방법은 GetHashCode()Equals()입니다. 두 가지가 같으면 ( Equals()참을 반환) 동일한 해시 코드를 가져야합니다. 예를 들어 "FooID를 반환합니다"; 는 AS GetHashCode()는 경기와 같은 것을합니다. 구현할 수도 IEquatable<Foo>있지만 선택 사항입니다.

class Foo : IEquatable<Foo> {
    public string Name { get; set;}
    public int FooID {get; set;}

    public override int GetHashCode() {
        return FooID;
    }
    public override bool Equals(object obj) {
        return Equals(obj as Foo);
    }
    public bool Equals(Foo obj) {
        return obj != null && obj.FooID == this.FooID;
    }
}

마지막으로, 다른 대안은 IEqualityComparer<T>동일한 작업 을 제공하는 것입니다.


FooID그룹의 식별자로 사용하려면 Foo 객체 대신 사전에서이를 키로 사용해야합니다.

Dictionary<int, List<Stuff>>

Foo객체를 키로 사용하는 경우 속성 만 고려하기 위해 GetHashCodeand Equals메소드를 구현 하면 FooID됩니다. Name가 늘어나는만큼 숙박 시설은 단지 죽은 무게 될 Dictionary우려했다, 그래서 당신은 그냥 사용하는 것이 Foo의 래퍼로서 int.

따라서 FooID값을 직접 사용하는 것이 좋으며 키를 사용 하여 Dictionary이미 지원하는 int것으로 구현할 필요는 없습니다 .

편집 :
당신이 사용하려는 경우 Foo키 어쨌든 같은 클래스의는 IEqualityComparer<Foo>쉽게 구현할 수 :

public class FooEqualityComparer : IEqualityComparer<Foo> {
   public int GetHashCode(Foo foo) { return foo.FooID.GetHashCode(); }
   public bool Equals(Foo foo1, Foo foo2) { return foo1.FooID == foo2.FooID; }
}

용법:

Dictionary<Foo, List<Stuff>> dict = new Dictionary<Foo, List<Stuff>>(new FooEqualityComparer());

Foo의 경우 object.GetHashCode () 및 object.Equals ()를 재정의해야합니다.

사전은 각 값에 대한 해시 버킷을 계산하기 위해 GetHashCode ()를 호출하고 두 Foo가 동일한 지 비교하기 위해 동일합니다.

Make sure to calculate good hash codes (avoid many equal Foo objects having the same hashcode), but make sure two equals Foos have the same hash code. You might want to start with the Equals-Method and then (in GetHashCode()) xor the hash code of every member you compare in Equals.

public class Foo { 
     public string A;
     public string B;

     override bool Equals(object other) {
          var otherFoo = other as Foo;
          if (otherFoo == null)
             return false;
          return A==otherFoo.A && B ==otherFoo.B;
     }

     override int GetHashCode() {
          return 17 * A.GetHashCode() + B.GetHashCode();
     }
}

I had the same problem. I can now use any object I've tried as a key due to overriding Equals and GetHashCode.

Here is a class that I built with methods to use inside of the overrides of Equals(object obj) and GetHashCode(). I decided to use generics and a hashing algorithm that should be able to cover most objects. Please let me know if you see anything here that doesn't work for some types of object and you have a way to improve it.

public class Equality<T>
{
    public int GetHashCode(T classInstance)
    {
        List<FieldInfo> fields = GetFields();

        unchecked
        {
            int hash = 17;

            foreach (FieldInfo field in fields)
            {
                hash = hash * 397 + field.GetValue(classInstance).GetHashCode();
            }
            return hash;
        }
    }

    public bool Equals(T classInstance, object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }
        if (classInstance.GetType() != obj.GetType())
        {
            return false;
        }

        return Equals(classInstance, (T)obj);
    }

    private bool Equals(T classInstance, T otherInstance)
    {
        List<FieldInfo> fields = GetFields();

        foreach (var field in fields)
        {
            if (!field.GetValue(classInstance).Equals(field.GetValue(otherInstance)))
            {
                return false;
            }
        }

        return true;
    }

    private List<FieldInfo> GetFields()
    {
        Type myType = typeof(T);

        List<FieldInfo> fields = myType.GetTypeInfo().DeclaredFields.ToList();
        return fields;
    }
}

Here is how it's used in a class:

public override bool Equals(object obj)
    {
        return new Equality<ClassName>().Equals(this, obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return new Equality<ClassName>().GetHashCode(this);
        }
    }

What about Hashtable class!

Hashtable oMyDic = new Hashtable();
Object oAnyKeyObject = null;
Object oAnyValueObject = null;
oMyDic.Add(oAnyKeyObject, oAnyValueObject);
foreach (DictionaryEntry de in oMyDic)
{
   // Do your job
}

In above way, you can use any object (your class object) as a generic Dictionary key :)

참고URL : https://stackoverflow.com/questions/634826/using-the-field-of-an-object-as-a-generic-dictionary-key

반응형