【问题标题】:How can I create a generic "example" object of (practically) any given type?如何创建(实际上)任何给定类型的通用“示例”对象?
【发布时间】:2012-02-20 20:15:23
【问题描述】:

我正在开发一个元数据生成器,它基本上可以为 REST API 自动生成文档。

其中一部分包括显示请求/响应类型,当然可以是 DTO。我想要的是对象的序列化 JSON(或 XML)版本,显示结构和占位符数据。 (序列化部分很简单,从创建对象开始就很难了)。例如,给定对象:

public class MyObject {
    public string Name { get; set; }
    public int Age { get; set; }
    public bool Active { get; set; }
}

我希望能够调用一些函数:

var obj = GetDefaultValue(typeof(MyObject));

得到等价于:

new MyObject { Name = string.Empty, Age = 0, Active = false };
// or in other words:  new MyObject { Name = default(string), Age = default(int), Active = default(bool) };

我有一些开始执行此操作的基本代码:

    /// <summary>
    /// Class to create a default value for a specified type.
    /// </summary>
    public abstract class DefaultValueGenerator
    {
        private DefaultValueGenerator() { }

        /// <summary>
        /// Creates a new default instance of type T.
        /// Requires that T has a parameter-less constructor, or can be created using <code>default(T)</code>
        /// </summary>
        /// <param name="T"></param>
        /// <returns></returns>
        public static object GetDefaultValue(Type T)
        {
            try
            {
                return System.Activator.CreateInstance(T, true);
                //TODO: if array type, also create a single item of that type
            }
            catch (Exception activatorException)
            {
                try
                {
                    // from http://stackoverflow.com/a/2490267/7913
                    var defaultGeneratorType = typeof(DefaultGenerator<>).MakeGenericType(T);

                    return defaultGeneratorType.InvokeMember(
                      "GetDefault",
                      BindingFlags.Static |
                      BindingFlags.Public |
                      BindingFlags.InvokeMethod,
                      null, null, new object[0]);
                }
                catch //(Exception defaultGeneratorException)
                {
                    throw new MissingMethodException(string.Format("No parameterless constructor defined for model {0}", T.Name), activatorException);
                }

            }

        }

        // from http://stackoverflow.com/a/2490267/7913
        private class DefaultGenerator<T>
        {
            public static T GetDefault()
            {
                return default(T);
            }
        }


    }

所以,使用这个你可以调用:

var obj = DefaultValueGenerator.GetDefaultValue(typeof(MyObject));

这个实现的一个问题是,如果你调用DefaultValueGenerator.GetDefaultValue(typeof(string)),它会抛出我捕获为activatorException 的异常,然后使用default 关键字。只是丑陋,因为我依赖一个例外..有更好的方法吗?


第二个问题是数组/集合。例如:DefaultValueGenerator.GetDefaultValue(typeof(List&lt;MyObject&gt;)) 创建一个 0 元素列表,然后将其序列化为 JSON 为 [] - 在文档方面不是很有帮助。我希望它生成一个元素。


第三个问题是嵌套类型。例如,如果我有:

public class MyContainerObject {
    public MyObject OtherObject { get; set; }
    public int SomeValue { get; set; }
}

我希望它生成等效的:

var obj = new MyContainerObject { 
    OtherObject = new MyObject { Name = string.Empty, Age = 0, Active = false },
    SomeValue = 0,
}

但实际上它会生成OtherObject为空值。


有人知道一些已经这样做的代码/库吗?否则,关于如何实现这一点的任何提示,并避免我指出的一些陷阱?有没有其他更容易解决的方法?

我希望它适用于内置的基本类型(字符串、int、guid 等)以及任何更复杂的对象——只要它们有一个无参数的构造函数(我很好限制,因为无论如何使用的类型都应该是 POCO/DTO)。

【问题讨论】:

标签: .net reflection activator


【解决方案1】:

完成重写

我看到您有 DefaultGenerator 的源代码。您可以创建一个 TryMakeGenericType 重载来消除丑陋的 try...catch 块。这应该使代码更优雅。它不会消除抛出异常的事实,但会隐藏它。

关于列表,有没有办法确定列表中存储的项目的类型?我认为一旦有了这个,渲染代码以插入代码以初始化该类型的成员应该是一件相对简单的事情。

嵌套类型似乎与您在使用列表时遇到的问题相同。事实上,我敢打赌,一旦你解决了一个问题,另一个问题的解决方案就会变得显而易见。但是,如果不查看所有来源,则很难判断。

我同意,如果有一个库已经这样做了,那就太好了。我很想在这里为我们的 XML API 找到类似的东西。在短期内,您可能不得不扩展现有资源,直到找到合适的替代方案。

【讨论】:

  • 不,我根本不担心数据表示。我想要一种方法基本上采用任何 System.Type 并将其转换为具有默认值的完整实例,以便我可以将其用作文档中的结构示例(通常显示为 JSON 和/或 XML)。
  • 是的,我想我应该澄清一下我还没有尝试编写嵌套/列表的东西。我真的更想知道是否有人知道图书馆或以前做过类似的事情。不幸的是,谷歌很难(.NET、通用、实例化等都提出了很多不相关的结果)。这就是我拥有的所有代码;其他一切都特定于获取 GetDefaultValue() 的结果,序列化为 JSON 并将其呈现在我的 html 视图中。
猜你喜欢
  • 2020-06-18
  • 1970-01-01
  • 2011-10-21
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多