生成类的所有可能的排列

时间:2009-04-06 19:10:12

标签: c# algorithm

我有以下课程。出于测试目的,我想获得类Client的所有可能的排列。我知道这个数字可能非常大,但现在这不是我的问题。

客户:否(int),名称(字符串),地址(地址对象)
地址:街道(字符串),国家(字符串)等

对于int类型的属性,我总是尝试相同的三个值(-1,0,1),用于string(null,string.Empty,“Hello World”等)。对于基本类型,它运作良好。但是,对于类Address,这是不同的。

简而言之,我正在尝试编写一个足够通用的方法来获取任何Type(类等)并获得所有可能的排列(换句话说:public IEnumerable GetPermutations(Type myType))。在.NET Reflection的帮助下,此方法将循环所有可设置的属性。

有人知道该怎么做吗?

由于

6 个答案:

答案 0 :(得分:4)

PEX测试框架做了一些事情。它试图提供方法参数的几种排列,以便涵盖潜在有用的测试用例。

答案 1 :(得分:2)

这是一个可以帮助你入门的课程,虽然我没有对它进行过多次测试。请注意,这仅适用于具有no-args构造函数的类,并且不适用于某些类型的递归类(例如,具有自己类型属性的类,例如树)。您还可能希望在静态构造函数中预先填充更多类。

public static class PermutationGenerator
{
    private static class Permutation<T>
    {
        public static IEnumerable<T> Choices { get; set; }
    }

    static PermutationGenerator()
    {
        Permutation<int>.Choices = new List<int> { -1, 0, 1 }.AsReadOnly();
        Permutation<string>.Choices = new List<string> { null, "", "Hello World" }.AsReadOnly();
    }

    public static IEnumerable<T> GetPermutations<T>()
    {
        if (Permutation<T>.Choices == null) {
            var props = typeof(T).GetProperties().Where(p => p.CanWrite);
            Permutation<T>.Choices = new List<T>(GeneratePermutations<T>(() => Activator.CreateInstance<T>(), props)).AsReadOnly();
        }
        return Permutation<T>.Choices;
    }

    private static IEnumerable GetPermutations(Type t) {
        var method = typeof(PermutationGenerator).GetMethod("GetPermutations", new Type[] {}).MakeGenericMethod(t);
        return (IEnumerable)(method.Invoke(null,new object[] {}));
    }

    private delegate T Generator<T>();

    private static IEnumerable<T> GeneratePermutations<T>(Generator<T> generator, IEnumerable<PropertyInfo> props)
    {
        if (!props.Any())
        {
            yield return generator();
        }
        else
        {
            var prop = props.First();
            var rest = props.Skip(1);

            foreach (var propVal in GetPermutations(prop.PropertyType))
            {
                Generator<T> gen = () =>
                {
                    var obj = generator();
                    prop.SetValue(obj, propVal, null);
                    return (T)obj;
                };
                foreach (var result in GeneratePermutations(gen, rest))
                {
                    yield return result;
                }
            }
        }
    }
}

答案 2 :(得分:1)

大多数非平凡的动态分配对象 - 比如字符串 - 没有可用的有限数量的不同“排列”。该字符串可以是你想要的,直到你的RAM耗尽。

所以这真的是一个完全Sisyphean的任务,除非你对你正在寻找什么样的排列设置更严格的限制,否则没有任何意义继续下去。

答案 3 :(得分:1)

你可以看看PEX

http://research.microsoft.com/en-us/projects/pex/default.aspx

这是一个集成在Visual Studio中的白盒测试生成工具。

答案 4 :(得分:0)

正如许多人所说,产生所有排列对于非平凡的类来说在计算上是不可行的。我必须做的,并取得了巨大的成功,正在为特定范围的输入生成一个类的所有排列;即,给定一个具有属性A,B和C的类,我想生成A = 1,A = 2,B = 1,C = 3和C = 4的所有排列,导致:

A = 1,B = 1,C = 3

A = 2,B = 1,C = 3

A = 1,B = 1,C = 4

A = 2,B = 1,C = 4

这种事情可以通过递归算法或一些非常优雅的LINQ查询来完成。 here上有一个相当详尽的文章,但它的编程量很大,如果你对你的集合理论有所帮助,它真的会有所帮助。

答案 5 :(得分:-1)

这就像是要求在1小时内将中国长城搬到太空。它无法完成。

你需要知道什么定义了每种类型的每种排列,甚至是你没有创建的类型,这是不可能的。