Return 检查匹配属性的 C# 对象列表中的单个对象

Return a single object from a list of C# objects checking for matching properties

我需要创建一个对象 'factory',其工作方式如下:

  1. 接受匹配对象类型的列表。
  2. 比较列表中的每个 属性 值以查看它们是否匹配。
  3. Returns 该对象类型的新单个实例,仅设置了匹配字段。

(为简单起见,我们假设所有属性都是字符串)

例如,从这个人物对象列表中:

Person1 { Name: "Bob", Job: "Policeman", Location: "London" }
Person2 { Name: "John", Job: "Dentist", Location: "Florida" }
Person3 { Name: "Mike", Job: "Dentist", Location: "London"  }
Person4 { Name: "Fred", Job: "Doctor", Location: "London"   }

如果我传入一个包含第 2 个人和第 3 个人的列表,它将 return 一个像这样的新人:

Name: "No Match", Job: "Dentist", Location "No Match"

如果我通过第 3 和第 4 个人,它将 return 一个新人:

Name: "No Match", Job: "No Match", Location "London"

到目前为止....
使用这个 SO 问题的答案 :
How to check if all list items have the same value and return it, or return an “otherValue” if they don’t?

我可以让这个 LINQ 为单个已知对象工作,但我需要它是通用的。
这仅涵盖一个特定的 属性,但我的对象有 30 多个属性。

var otherValue="No Match"
var matchingVal= people.First().Job;
return people.All(x=>x.Job== matchingVal) ? matchingVal: otherValue; 

我也知道我可以使用反射来获取对象中的属性列表。但是如何将所有这些组合成一个 'factory' 是无法理解的。

我不认为这是一个独特的问题,但我在任何搜索中都找不到完整的解决方案。也许那里已经有一个 Nuget 包可以帮助我?

感谢收到所有建议。

您的输入是某种特定类型对象的枚举,您必须创建一个相同类型的对象,其中填充了所有属性,所有值都相同。这可以通过这样的方式完成:

private static T GetCommonProperties<T>(IEnumerable<T> source) where T : new()
{
    var first = true;
    var common = new T();
    var props = typeof(T).GetProperties();

    foreach (var item in source)
    {
        if (first)
        {
            first = false;

            foreach (var prop in props)
            {
                var value = prop.GetValue(item, null);
                prop.SetValue(common, value);
            }
        }
        else
        {
            foreach (var prop in props)
            {
                var itemValue = prop.GetValue(item, null);
                var commonValue = prop.GetValue(common, null);

                if ((dynamic)itemValue != (dynamic)commonValue)
                {
                    prop.SetValue(common, GetDefault(prop.PropertyType));
                }

            }
        }
    }

    return common;
}

给定的方法并不是真正最优的,因为它使用 dynamic 技巧来解决装箱值的比较问题。同样获取特定类型的默认值也可以通过这种通用方法实现:

private static object GetDefault(Type t)
{
    return typeof(Program)
        .GetMethod(nameof(GetDefaultValue), BindingFlags.NonPublic | BindingFlags.Static)
        .MakeGenericMethod(t)
        .Invoke(null, null);
}

private static T GetDefaultValue<T>()
{
    return default;
}

但也可以提供 switch 语句或 Dictionary<Type, object> 如果没有可用的匹配项,returns 所需的默认值。

最后但同样重要的是,另一个可能的性能改进是从 props 变量中删除所有 PropertyInfo 条目,因为对于任何下一个即将到来的对象,此检查不再需要并且相同方式,当没有更多的道具可用时,循环可以提前退出。

可以找到一个工作示例 here