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).