Как создать реализацию динамического равенства, в которой вы можете передать имена свойств для сравнения?

Скажем, у меня есть объект Person со свойствами ниже:

    public class Person
    {
        public int ID { get; set; }
        public int EmployeeNo { get; set; }
        public string JobDescription { get; set; }
        public string Code { get; set; }
    }

Как бы я динамически проверить равенство конкретных свойств по имени?

например.

var dynamicEqualityComparer = RetrieveDynamicEqualityComparer("ID", "JobDescription");
var intersectedPersons = listOfPerson1.Intersect(listOfPerson2, dynamicEqualityComparer);

Приведенный выше фрагмент кода будет использовать метод пересечения linq по умолчанию с использованием динамически сгенерированного метода сравнения на равенство, который сравнивает только поля "Я БЫ" а также "Описание работы".

Я бы предположил, что что-то вроде этого было бы легко найти, но до сих пор не удалось найти ничего подобного.

 SamuelDavis10 июн. 2013 г., 03:50
Дон»Если у вас нет доступа к классу во время компиляции, класс создается с помощью отражения.
 Chris Sinclair10 июн. 2013 г., 03:42
Это должно быть через отражение? Если вы знаете это во время компиляции, почему бы не сделать общийRetrieveDynamicEqualityComparer это занимаетFunc? Так, например,var comparer = new RetrieveDynamicEqualityComparer((person1, person2) => person1.ID == person2.ID && person1.JobDescription == person2.JobDescription);, Наверное, мог бы даже использоватьLambdaExpression чтобы сделать это немного проще, ссылаясь на свойства времени компиляции.
 lightbricko10 июн. 2013 г., 03:08
Вы можете использовать отражения и выражения. Что-то подобное смотритеstackoverflow.com/a/844855/1105687 а такжеstackoverflow.com/a/986617/1105687

Ответы на вопрос(2)

Поместите это в свой личный класс, тогда с вашим экземпляром вы можете назвать равными

    public override bool Equals(object obj)
            {
                return obj.ToString() == this.ToString();
            }

           public override int GetHashCode()
           {
               return this.ToString().GetHashCode();
           }

            public override string ToString()
            {
                string myState;
                myState = string.Format("[ID: {0};EmployeeNo : {1}; JobDescription: {2};Code :{3}]",ID,EmployeeNo,JobDescription,Code);
                return myState;
            }

поскольку переопределение tostring учитывает все данные состояния, в override equals вы просто используете свою собственную реализацию ToString ().

public int Compare(Person x, Person y)
        {
            if (x.ID == y.ID && x.JobDescription == y.JobDescription) 
                return 0;

            return (x.ID > y.ID) ? 1 : -1;//here you put what condition to return here i put ID just
                                          //for clarity,if u want just return -1 for ex:
        } 

это реализация IComparer <> интерфейс типа Person

 SamuelDavis10 июн. 2013 г., 03:17
Это нек сожалению, я не могу ответить на мой вопрос. В моем примере RetrieveDynamicEqualityComparer ("Я БЫ", "Описание работы") Я только хочу проверить два свойства "Я БЫ" а также "Описание работы", Другие свойства могут быть заполнены чем-либо еще и недолжно быть равным. Равенство должно определяться двумя переданными свойствами.
 SamuelDavis10 июн. 2013 г., 06:25
К сожалению, ваше редактирование также не было динамическим. Мне потребовалось, чтобы параметры для проверки были переданы. Я решил эту проблему. Вы можете увидеть мой ответ, если хотите.
Решение Вопроса

Решение, к которому я пришел, приведено ниже:

Класс сравнения равенства выглядит так:

public class CustomPropertyEqualityComparer: IEqualityComparer where T : class
{
    private readonly string[] _selectedComparisonProperties;

    public CustomPropertyEqualityComparer(params string[] selectedComparisonProperties)
    {
        _selectedComparisonProperties = selectedComparisonProperties;
    }

    public bool Equals(T x, T y)
    {
        if (x != null && y != null && x.GetType() == y.GetType())
        {
            var type = x.GetType();

            var comparableProperties = new List(_selectedComparisonProperties);

            var objectProperties = type.GetProperties();

            var relevantProperties = objectProperties.Where(propertyInfo => comparableProperties.Contains(propertyInfo.Name));

            foreach (var propertyInfo in relevantProperties)
            {
                var xPropertyValue = type.GetProperty(propertyInfo.Name).GetValue(x, null);

                var yPropertyValue = type.GetProperty(propertyInfo.Name).GetValue(y, null);

                if (xPropertyValue != yPropertyValue && (xPropertyValue == null || !xPropertyValue.Equals(yPropertyValue)))
                {
                    return false;
                }

            }
            return true;
        }
        return x == y;
    }

    public int GetHashCode(T obj)
    {
        var type = typeof(T);

        var objectProperties = type.GetProperties();

        return objectProperties.Sum(property => property.GetHashCode());
    }
}

Чтобы создать этот класс, вы передаете список строк, представляющих имена свойств объектов.

Чтобы вызвать этот класс, я использовал следующий фрагмент кода:

var groupKey = new List {"EmployeeNo", "ID"}.ToArray();
var customEqualityComparer = new CustomPropertyEqualityComparer(groupKey);

Это создает пользовательский компаратор равенства для любого класса со свойствами "Сотрудник №" а также "Я БЫ".

Я использовал этот компаратор при проверке, если две таблицы содержат одинаковые записи, где равенство неt обязательно означает, что все поля равны ..

var existInBothTables = table1.Intersect(table2, customEqualityComparer).ToList();
 kassi25 февр. 2015 г., 15:27
Это действительно хорошее решение! Один вопрос: если вы сейчас сделаете ListNew = ListA.Except (ListB, CustomEqualityComparer) .ToList () и допустим, что ListA имеет дублирующиеся элементы, ListNew будет содержать только один из дубликатов, есть идеи, как сохранить дублирующиеся элементы? Заранее спасибо!

Ваш ответ на вопрос