根据属性名称数组创建对象的子集

时间:2015-06-23 19:23:43

标签: c# .net linq reflection

我有一个类和一组属性名定义如下:

public class Dog {
    public string Name { get; set; }
    public string Breed { get; set; }
    public int Age { get; set; }
}

var desiredProperties = new [] {"Name", "Breed"};

我还有一个返回狗对象列表的方法:

List<Dog> dogs = GetAllDogs();

有没有办法可以返回只包含dogs数组中定义的属性的desiredProperties子集?最终,此结果列表将序列化为JSON。

我一直在努力解决这个问题一段时间,考虑到允许用户指定任何属性组合(假设它们都是有效的)作为数组中的输出。还有一些例子:

var desiredProperties = new [] {"Name", "Age"};
// Sample output, when serialized to JSON:
// [
//   { Name: "Max", Age: 5 },
//   { Name: "Spot", Age: 2 }
// ]

var desiredProperties = new [] {"Breed", "Age"};
// [
//   { Breed: "Scottish Terrier", Age: 5 },
//   { Breed: "Cairn Terrier", Age: 2 }
// ]

3 个答案:

答案 0 :(得分:4)

你可以编写一个函数来做到这一点。使用下面的扩展方法。

public static class Extensions
{
    public static object GetPropertyValue(this object obj, string propertyName)
    {
        return obj.GetType().GetProperty(propertyName).GetValue(obj);
    }

    public static List<Dictionary<string, object>> FilterProperties<T>(this IEnumerable<T> input, IEnumerable<string> properties)
    {
        return input.Select(x =>
        {
            var d = new Dictionary<string, object>();
            foreach (var p in properties)
            {
                d[p] = x.GetPropertyValue(p);
            }
            return d;
        }).ToList();
    }
}

测试就像

var dogs = GetAllDogs();

var f1 = dogs.FilterProperties(new[]
{
    "Name", "Age"
});

var f2 = dogs.FilterProperties(new[]
{
    "Breed", "Age"
});

Console.WriteLine(JsonConvert.SerializeObject(f1));
Console.WriteLine(JsonConvert.SerializeObject(f2));

,结果是

  

[{&#34;名称&#34;:&#34;现货&#34;&#34;年龄&#34;:2},{&#34;名称&#34;:&#34;最大和#34;&#34;年龄&#34;:5}]
  [{&#34; Breed&#34;:&#34; Cairn Terrier&#34;,&#34; Age&#34;:2},{&#34;品种&#34;:&#34;苏格兰梗&# 34;,&#34;年龄&#34;:5}]

答案 1 :(得分:0)

我不知道这是否是最有效的方式,但它是一种方式:

var list = new List<Dog>();
list.Add(new Dog {Name = "Max", Breed = "Bull Terrier", Age = 5});
list.Add(new Dog {Name = "Woofie", Breed = "Collie", Age = 3});
var desiredProperties = new[] {"Name", "Breed"};
var exportDogs = new List<Dictionary<string, object>>();
foreach(var dog in list)
{
    var exportDog = new Dictionary<string, object>();
    foreach(var property in desiredProperties)
    {
        exportDog[property] = dog.GetType().GetProperty(property).GetValue(dog, null);
    }
    exportDogs.Add(exportDog);
}
var output = JsonConvert.SerializeObject(exportDogs);

输出将如下所示:

[{"Name":"Max","Breed":"Bull Terrier"},{"Name":"Woofie","Breed":"Collie"}]

但是,如果你需要动态访问属性,那么做这样的事情要好得多:

var output = list.Select(dog => new {dog.Name, dog.Breed});

然后只序列化输出。

答案 2 :(得分:0)

像这样......没有经过测试...

    var desiredProperties = new [] {"Name", "Breed"};
    var lst = (from asm in AppDomain.CurrentDomain.GetAssemblies()
                        from asmTyp in asm.GetTypes()
                        where typeof(dog).IsAssignableFrom(asmTyp) && desiredProperties.All(p=> PropertyExists(asmTyp, p))
                        select asmTyp).ToArray();

    private bool PropertyExists(Type dogType, string name)
    {
        bool ret=true;
        try{ dogType.GetProperty(name);}
        catch{ret=false};

        return ret;
    }