Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取具有属性组合的类实例集合_C#_Linq_Reflection_Attributes_Combinatorics - Fatal编程技术网

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();