Last week while I was building a wiki generator and realized that I have to generate the possible responses of an API. Which means I need to get an object with all meaningful values in it. For example:

{
  "value": {
    "id": "69c8981d-3498-48ff-8126-fcee0e8c8929",
    "conversationId": 0,
    "ats": [
      {
        "targetUserId": "an example string."
      }
    ],
    "senderId": "an example string.",
    "sender": {
      "email": "an example string.",
      "isOnline": true,
      "id": "an example string.",
      "nickName": "an example string.",
      "iconFilePath": "an example string."
    },
    "sendTime": "2019-12-25T08:52:03.2898292Z",
    "content": "an example string.",
    "read": true
  },
  "code": 0,
  "message": "an example string."
}

Reading and writing that JSON is super easy. But how can we build it without knowing the structure of the class? So I built an example object injector.

To build an object, I need to give some example values based on the type input.

public static object Make(Type type)
{
    if (type == typeof(string))
    {
        return "an example string.";
    }
    else if (type == typeof(int) || type == typeof(int?))
    {
        return 0;
    }
    else if (type == typeof(DateTime) || type == typeof(DateTime?))
    {
        return DateTime.UtcNow;
    }
    else if (type == typeof(Guid) || type == typeof(Guid?))
    {
        return Guid.NewGuid();
    }
    else if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?))
    {
        return DateTimeOffset.UtcNow;
    }
    else if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
    {
        return TimeSpan.FromMinutes(37);
    }
    else if (type == typeof(bool) || type == typeof(bool?))
    {
        return true;
    }
    // not finihsed..
}

For example, if you require a bool, I will return you true. If you require a string, I will return you an example string..

But what if the program requires an array or a list? Consider the user wants a List<string>. First, we need to get the type string.

// continue
else if (type.IsGenericType && type.GetGenericTypeDefinition().GetInterfaces().Any(t => t.IsAssignableFrom(typeof(IEnumerable))))
{
    var itemType = type.GetGenericArguments()[0];
    // not finished.
}

While we currently know the type of the array element, we still can't just return Make(itemType). For in some cases the itemType might be abstract. Consider the following cases:

public abstract class Car
{

}

public class Truck : Car
{

}

public class BenchCar : Car
{

}

When the input is List<Car>, the best response is new List() { new Truck(), new BenchCar() } which indicates all possible value structures in the collection.

So we need to search for all possible types to fill the collection. Write a new method like this:

public static IList GetArrayWithInstanceInherts(Type itemType)
{
    var listType = typeof(List<>);
    var constructedListType = listType.MakeGenericType(itemType);
    var instance = (IList)Activator.CreateInstance(constructedListType);
    if (!itemType.IsAbstract)
    {
        instance.Add(Make(itemType));
    }
    foreach (var item in Assembly.GetEntryAssembly().GetTypes().Where(t => !t.IsAbstract).Where(t => t.IsSubclassOf(itemType)))
    {
        instance.Add(Make(item));
    }
    return instance;
}

That method will return an IList with all possible instances which inherit the input itemType.

Continue changing the method Make to return the list:

// List
else if (type.IsGenericType && type.GetGenericTypeDefinition().GetInterfaces().Any(t => t.IsAssignableFrom(typeof(IEnumerable))))
{
    var itemType = type.GetGenericArguments()[0];
    return GetArrayWithInstanceInherts(itemType);
}

As for the array, we also need to get the type of its element and inject the list.

// Array
else if (type.GetInterface(typeof(IEnumerable<>).FullName) != null)
{
    var itemType = type.GetElementType();
    var list = GetArrayWithInstanceInherts(itemType);
    var array = Array.CreateInstance(itemType, list.Count);
    list.CopyTo(array, 0);
    return array;
}

Now, for all input with common types and collections, we can return an instance as an example correctly. But what if the input cascades another object?

We also need to provide a method to get an object directly.

public static object GenerateWithConstructor(Type type)
{
    if (type.IsAbstract)
    {
        return null;
    }
    else if (!type.GetConstructors().Any(t => t.IsPublic))
    {
        return null;
    }
    else
    {
        return Assembly.GetAssembly(type).CreateInstance(type.FullName);
    }
}

This returns an example object from the input user input. But consider the following cases:

public class MyClass
{
    public MyClass(string input)
    {
        MyString = input;
    }

    public string MyString { get; set; }
}

The class MyClass doesn't have a constructor without any parameters. We have to inject the input to build the object.

else if (type.GetConstructors().Where(t => t.IsPublic).Any() && !type.IsAbstract)
{
    // Has a constructor, and constructor has some arguments.
    var constructor = type.GetConstructors()[0];
    var args = constructor.GetParameters();
    object[] parameters = new object[args.Length];
    for (int i = 0; i < args.Length; i++)
    {
        var requirement = args[i].ParameterType;
        parameters[i] = Make(requirement);
    }
    return Assembly.GetAssembly(type).CreateInstance(type.FullName, true, BindingFlags.Default, null, parameters, null, null);
}

This finishes our GenerateWithConstructor method. It finally looks like this:

public static object GenerateWithConstructor(Type type)
{
    // Has default constructor.
    if (type.GetConstructors().Count() == 1 &&
        type.GetConstructors()[0].GetParameters().Count() == 0 &&
        !type.IsAbstract)
    {
        return Assembly.GetAssembly(type).CreateInstance(type.FullName);
    }
    else if (type.GetConstructors().Where(t => t.IsPublic).Any() && !type.IsAbstract)
    {
        // Has a constructor, and constructor has some arguments.
        var constructor = type.GetConstructors()[0];
        var args = constructor.GetParameters();
        object[] parameters = new object[args.Length];
        for (int i = 0; i < args.Length; i++)
        {
            var requirement = args[i].ParameterType;
            parameters[i] = Make(requirement);
        }
        return Assembly.GetAssembly(type).CreateInstance(type.FullName, true, BindingFlags.Default, null, parameters, null, null);
    }
    else if (type.IsAbstract)
    {
        return null;
    }
    else if (!type.GetConstructors().Any(t => t.IsPublic))
    {
        return null;
    }
    else
    {
        return Assembly.GetAssembly(type).CreateInstance(type.FullName);
    }
}

And go back to our Make method. To finally return the cascaded object, just call GenerateWithConstructor to get it.

else
{
    var instance = GenerateWithConstructor(type);
    return instance;
}

This looks fine, but still not finished. The properties in your constructed object may still contain other properties. We also need to inject it.

The best practice to inject all properties is to do it recursively. Just call the Make method inside the Make method.

else
{
    var instance = GenerateWithConstructor(type);
    if (instance != null)
    {
        foreach (var property in instance.GetType().GetProperties())
        {
            if (property.SetMethod != null)
            {
                property.SetValue(instance, Make(property.PropertyType));
            }
        }
    }
    return instance;
}

Now everything works fine. Finally, our code looks like this:

public static object Make(Type type)
{
    if (type == typeof(string))
    {
        return "an example string.";
    }
    else if (type == typeof(int) || type == typeof(int?))
    {
        return 0;
    }
    else if (type == typeof(DateTime) || type == typeof(DateTime?))
    {
        return DateTime.UtcNow;
    }
    else if (type == typeof(Guid) || type == typeof(Guid?))
    {
        return Guid.NewGuid();
    }
    else if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?))
    {
        return DateTimeOffset.UtcNow;
    }
    else if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
    {
        return TimeSpan.FromMinutes(37);
    }
    else if (type == typeof(bool) || type == typeof(bool?))
    {
        return true;
    }
    // List
    else if (type.IsGenericType && type.GetGenericTypeDefinition().GetInterfaces().Any(t => t.IsAssignableFrom(typeof(IEnumerable))))
    {
        var itemType = type.GetGenericArguments()[0];
        return GetArrayWithInstanceInherts(itemType);
    }
    // Array
    else if (type.GetInterface(typeof(IEnumerable<>).FullName) != null)
    {
        var itemType = type.GetElementType();
        var list = GetArrayWithInstanceInherts(itemType);
        var array = Array.CreateInstance(itemType, list.Count);
        list.CopyTo(array, 0);
        return array;
    }
    else
    {
        var instance = GenerateWithConstructor(type);
        if (instance != null)
        {
            foreach (var property in instance.GetType().GetProperties())
            {
                if (property.SetMethod != null)
                {
                    property.SetValue(instance, Make(property.PropertyType));
                }
            }
        }
        return instance;
    }
}

It's time for us to test it! Build some classes and try to inject an object!

    public abstract class Conversation
    {

    }

    public class PConversation : Conversation
    {
        public string MYCName { get; set; }
    }

    public class GConversation : Conversation
    {
        public string[] MGName { get; set; }

    }
    public enum Gender
    {
        male,
        female
    }
    public class Son
    {
        public string Name { get; set; }
        public Gender Gender { get; set; }
    }
    public class MyClass
    {
        public int Count { get; set; }
        public string Message { get; set; }

        public List<string> Teachers1 { get; set; }
        public string[] Teachers2 { get; set; }
        public List<Son> Sons { get; set; }
        public Son[] Sons2 { get; set; }
        public Son MySon { get; set; }
        public bool IsMale { get; set; }
        public Conversation[] Conversations { get; set; }
        public List<Conversation> Conversations2 { get; set; }
    }

Test it with:

static void Main(string[] args)
{
    var instance = Make(typeof(MyClass));
    var finalresult = JsonConvert.SerializeObject(instance, Formatting.Indented);
    Console.WriteLine(finalresult);
}

Result:

{
  "Count": 0,
  "Message": "an example string.",
  "Teachers1": [
    "an example string."
  ],
  "Teachers2": [
    "an example string."
  ],
  "Sons": [
    {
      "Name": "an example string.",
      "Gener": 0
    }
  ],
  "Sons2": [
    {
      "Name": "an example string.",
      "Gener": 0
    }
  ],
  "MySon": {
    "Name": "an example string.",
    "Gener": 0
  },
  "IsMale": true,
  "Conversations": [
    {
      "MYCName": "an example string."
    },
    {
      "MGName": [
        "an example string."
      ]
    }
  ],
  "Conversations2": [
    {
      "MYCName": "an example string."
    },
    {
      "MGName": [
        "an example string."
      ]
    }
  ]
}