How can I create a generic "example" object of (practically) any given type?

153 Views Asked by At

I'm working on a metadata generator that basically auto-generates documentation for a REST API.

Part of this includes showing the request/response types, which of course can be DTOs. What I'd like is a serialized JSON (or XML) version of the object, showing the structure and placeholder data. (The serialization part is easy, it's creating the object to begin with that's hard). So for example, given the object:

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

I want to be able to call some function:

var obj = GetDefaultValue(typeof(MyObject));

and get the equivalent of:

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

I have some basic code that starts to do this:

    /// <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);
            }
        }


    }

So, using this you can call:

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

One problem this implementation is that if you call DefaultValueGenerator.GetDefaultValue(typeof(string)) it throws the exception I catch as activatorException and then uses the default keyword. Just ugly because I'm relying on an exception.. is there a better way?


Second issue is arrays/collections. For example: DefaultValueGenerator.GetDefaultValue(typeof(List<MyObject>)) creates a 0-element list, which in turn serializes to JSON as [] -- not very helpful in terms of documentation. I'd like this to generate one element.


Third issue is nested types. For example, if I have:

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

I'd like this to generate the equivalent of:

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

but in fact, it generates OtherObject as a null value.


Anyone know of some code/library that does this already? Otherwise, any tips on how to accomplish this, and avoid some pitfalls I've pointed out? Is there a different way to solve this that would be easier?

I'd like this to work for built-in basic types (string, int, guid, etc) as well as any more complex objects -- so long as they have a parameter-less constructor (I am fine with that limitation, since the types used should be POCO's/DTO's anyway).

1

There are 1 best solutions below

2
On

COMPLETE Rewrite

I see that you have the source code for the DefaultGenerator. You could create a TryMakeGenericType overload to eliminate the ugly try...catch block. That should make the code more elegant. It won't eliminate the fact that an exception is being thrown, but it will hide it.

Regarding lists, is there no way to determine the type of the items stored in the list? I would think that once you have this, it should be a relatively straightforward matter to render the code to insert the code to initialize member of that type.

Nested types appear to be the same problem you're running into with lists. In point of fact, I'd wager that once you solve the one problem, the solution to the other would become readily apparent. Without seeing all of the source, though, it's hard to tell.

I agree, it would be very nice to have a library that already does this. I would love to find something like it for our XML API here. You're likely going to have to extend what you have, in the short term, until a suitable alternative can be found.