创建具有多个属性的对象集合

5

我有一个对象,其中包含多个布尔(和整数)属性。我想创建一个对象集合,其中包含很多不同的属性,以便用于测试。

例如:

public class A
{
     public int value {get; set;} //want to try beetween 0 and 5
     public bool foo {get; set;}
     public bool bar {get; set;}
     public bool boo {get; set;}
}

对于这个例子,我想要一个包含24个元素的列表,其中value的值为0/1/2/3/4/5,foobar的值为true/false,但是boo始终为false。
我可以使用24行代码来完成。但是这太多了,如果我有一个bool变量,它会使代码行数翻倍。
我可以针对每个属性使用一个循环,但我认为这样嵌套太多循环不是一个好方法。我也可以使用反射来完成,但我认为这太麻烦了,不是吗?
我认为还有一种更好的方法来完成这个任务,但我找不到它。

2
“我认为嵌套太多的循环不是一个好的方式。” 为什么不呢?在这里似乎是完全合理的事情... - tolanj
看一下Linq笛卡尔积的例子,应该很容易也很好构建。 - Mike Miller
可能是生成所有可能组合的重复问题。 - Mike Miller
3个回答

3
这个老的基于循环的方法有什么问题?
var boolVals = new[] { true, false };
var intVals = new[] { 0, 1, 2, 3, 4, 5 };

var myList = new List<A>();

foreach(var foo in boolVals) {
    foreach(var value in intVals) {
        foreach(var bar in boolVals) {
            foreach (var boo in boolVals) {
                myList.Add(new A { value = value, foo = foo, bar = bar, boo = boo });
            }
        }
    }
}

每添加一个属性,您都需要添加一个新的嵌套,并循环此属性可能具有的适当值集。

这种方法可以在几行易于阅读的代码中填充所有可能的值组合。

当然,它看起来有点丑陋。但是每添加一个属性只增加一层嵌套。


1

既然你没有明确要求全排列解决方案,我建议采用随机方法。你可以使用构造函数...

public class A
{
  public int value {get; set;} //want to try beetween 0 and 5
  public bool foo {get; set;}
  public bool bar {get; set;}
  public bool boo {get; set;}

  public A()
  {
     // initialize value, foo, bar, boo with desired default / random here

  }
}

var myList = new List<A>();
for (int i=0; i<=24; i++) myLyst.add(new A());

这对我来说看起来很易读和易维护。如果需要,您还可以向 new A() 传递参数并使用它来计算第 n 个排列,但我猜这超出了问题的范围。

0

您可以使用反射和数据结构来跟踪每个属性的值(通过等效索引)来实现此操作。

这将自动考虑类中的所有属性,并且您可以通过简单地向ValuesFor字典添加内容来扩展其他属性类型。

using System;
using System.Collections.Generic;
using System.Reflection;

public class Program
{
    private static Dictionary<string, object[]> ValuesFor = new Dictionary<string, object[]>()
    {
        { typeof(int).ToString(), new object[] { 0, 1, 2, 3, 4, 5 } },
        { typeof(bool).ToString(), new object[] { true, false } }
    };



    public static void Main()
    {
        var properties = typeof(A).GetProperties(BindingFlags.Instance | BindingFlags.Public);
        int[] valueIndices = new int[properties.Length];

        do
        {
            createObject(properties, valueIndices);
        } while (setNext(properties, valueIndices));

        Console.ReadKey();
    }

    /// <summary>
    /// This updates the valueIndex array to the next value
    /// </summary>
    /// <returns>returns true if the valueIndex array has been updated</returns>
    public static bool setNext(PropertyInfo[] properties, int[] valueIndices)
    {
        for (var i = 0; i < properties.Length; i++)
        {
            if (valueIndices[i] < ValuesFor[properties[i].PropertyType.ToString()].Length - 1) {
                valueIndices[i]++;
                for (var j = 0; j < i; j++)
                    valueIndices[j] = 0;
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Creates the object
    /// </summary>
    public static void createObject(PropertyInfo[] properties, int[] valueIndices)
    {
        var a = new A();
        for (var i = 0; i < properties.Length; i++)
        {
            properties[i].SetValue(a, ValuesFor[properties[i].PropertyType.ToString()][valueIndices[i]]);
        }

        print(a, properties);
    }



    public static void print(object a, PropertyInfo[] properties)
    {
        Console.Write("Created : ");
        for (var i = 0; i < properties.Length; i++)
            Console.Write(properties[i].Name + "=" + properties[i].GetValue(a) + " ");
        Console.Write("\n");
    }



    public class A
    {
        public int value { get; set; }
        public bool foo { get; set; }
        public bool bar { get; set; }
        public bool boo { get; set; }
    }
}

当前,createObject仅创建对象并调用print打印对象。相反,您可以将其添加到集合中并使用它运行您的测试(或直接将您的测试放在print的位置)。


Fiddle - https://dotnetfiddle.net/oeLqc5

代码编辑器 - https://dotnetfiddle.net/oeLqc5


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接