C# 获取具有属性组合的类实例集合
我遇到了以下问题 考虑以下简单属性C# 获取具有属性组合的类实例集合,c#,linq,reflection,attributes,combinatorics,C#,Linq,Reflection,Attributes,Combinatorics,我遇到了以下问题 考虑以下简单属性 [AttributeUsage(AttributeTargets.Property)] public class CombinationsAttribute : Attribute { public object[] PossibleValues { get; private set; } public CombinationsAttribute(params object[] values) { this.Possib
[AttributeUsage(AttributeTargets.Property)]
public class CombinationsAttribute : Attribute
{
public object[] PossibleValues { get; private set; }
public CombinationsAttribute(params object[] values)
{
this.PossibleValues = values;
}
}
下面是属性使用示例-只是一些具有一些伪属性的类,进入属性的值数组始终是属性类型
public class MyClass
{
[Combinations(1, 2, 3, 4, 5)]
public int IntProperty1 { get; set; }
[Combinations(10, 15, 20, 25, 30)]
public int IntProperty2 { get; set; }
[Combinations("X", "Y", "Z")]
public string StringProperty { get; set; }
}
在这个例子中,我想得到所有组合的所有实例5*5*3。我怎样才能尽可能少地编写代码呢
编辑:我不知道MyClass类-有许多具有公共属性的类具有CombinationsAttribute,我需要为其计算所有可能的组合。这些类始终具有无参数构造函数
可视化的预期结果示例伪c:
List<MyClass> Combinations = GetCombinationMagicFunction(typeof(MyClass));
List[0] = MyClass { IntProperty1 = 1, IntProperty2 = 10, StringProperty = "X" }
List[1] = MyClass { IntProperty1 = 1, IntProperty2 = 10, StringProperty = "Y" }
List[2] = MyClass { IntProperty1 = 1, IntProperty2 = 10, StringProperty = "Z" }
List[2] = MyClass { IntProperty1 = 1, IntProperty2 = 15, StringProperty = "X" }
...
List[74] = MyClass { IntProperty1 = 5, IntProperty2 = 30, StringProperty = "Z" }
我的基本出发点是沿着这些路线。您需要使用一点反射来设置值,但您应该了解这一点
var properties = type.GetProperties()
.Where(prop => prop.IsDefined(typeof(CombinationsAttribute), false));
foreach(var prop in properties)
{
allCombinations.Add(instance);
var attributes = (CombinationsAttribute[])prop.GetCustomAttributes(typeof(CombinationsAttribute), false);
foreach(var value in attributes)
{
}
}
用法:
var list = BuildCombinations<MyClass>().ToList();
在Eric Lippert的帮助下: 用法:
var list = BuildCombinations<MyClass>().ToList();
进入属性的值数组始终是属性类型,但您有[CombinationsX,Y,Z]公共int StringProperty…嗯,我想这个问题没有简明的解决方案,但我还是要尝试一下,因为它仍然比我的解决方案短两倍。从给定的解决方案开始工作,最简洁。谢谢:
private static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(emptyProduct, (accumulator, sequence) => accumulator.SelectMany(accseq => sequence.Select(item => accseq.Concat(new[] { item }))));
}
public static IEnumerable<T> BuildCombinations<T>() where T : new()
{
var query = from prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
let attributes = prop.GetCustomAttributes(typeof(CombinationsAttribute), false)
where attributes != null && attributes.Length != 0
let attribute = (CombinationsAttribute)attributes[0]
select attribute.PossibleValues.Select(value => new { prop, value })
;
var combinations = CartesianProduct(query);
foreach (var combination in combinations)
{
var item = new T();
foreach (var pair in combination)
{
pair.prop.SetValue(item, pair.value, null);
}
yield return item;
}
}
var list = BuildCombinations<MyClass>().ToList();