For some time I am trying to make a mocking library for C# that mocks objects with just 1 line of code. I am using abstract factory pattern to know what is the object's type so that I can work with concrete factories.

I have the following Abstract factory class which I am not very happy with.   

    public class MockContext<T>
    {
       public T CreateMockObject()
       {
          IFactory<T> factory = null;

         if (typeof(T).IsPrimitive || typeof(T) == typeof(string) || typeof(T) == typeof(decimal))
         {
            factory = new PrimitiveFactory<T>();
         }
         else if (typeof(T).IsArray)
         {
            factory = new ArrayFactory<T>();
         }
         else if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
         {
            factory = new CollectionFactory<T>();
         }
         else if (typeof(T).IsClass && typeof(T) != typeof(string))
         {
            factory = new ClassFactory<T>();
         }

          return factory.Create();
      }
     }
    }

Which gets called by the following class

       public class Mocker
       {
          public T MockObject<T>()
          {
             MockContext<T> context = new MockContext<T>();
             T mockObject = context.CreateMockObject();
    
             return mockObject;
          }
       }

This abstract factory instantiates other factories depending on of the object.

Here is my class factory:

       public class ClassFactory<T> : IFactory<T>
       {
          public T Create()
          {
             T mockObject = (T)Activator.CreateInstance(typeof(T));
             IEnumerable<PropertyInfo> properties = typeof(T).GetProperties().Where(p => p.CanWrite);
    
             GenericMethodInvokerUtil method = new GenericMethodInvokerUtil();
    
             foreach (PropertyInfo property in properties)
             {
                if (property.PropertyType == typeof(T))
                   throw new Exception("Circular properties are not supported!");
    
                method.InvokeMockObject<T>(property.PropertyType, property, mockObject);
             }
    
             return mockObject;
          }
       }

Here is my Primitive factory:

       public class PrimitiveFactory<T> : IFactory<T>
       {
          private readonly Dictionary<Type, IPrimitiveFactory<T>> _primitiveFactories = new Dictionary<Type, IPrimitiveFactory<T>>()
          {
             { typeof(string), new StringFactory() as IPrimitiveFactory<T> },
             { typeof(bool), new BooleanFactory() as IPrimitiveFactory<T> },
             { typeof(byte), new ByteFactory() as IPrimitiveFactory<T> },
             { typeof(sbyte), new SbyteFactory() as IPrimitiveFactory<T> },
             { typeof(char), new CharFactory() as IPrimitiveFactory<T> },
             { typeof(decimal), new DecimalFactory() as IPrimitiveFactory<T> },
             { typeof(double), new DoubleFactory() as IPrimitiveFactory<T> },
             { typeof(float), new FloatFactory() as IPrimitiveFactory<T> },
             { typeof(int), new IntFactory() as IPrimitiveFactory<T> },
             { typeof(uint), new UintFactory() as IPrimitiveFactory<T> },
             { typeof(long), new LongFactory() as IPrimitiveFactory<T> },
             { typeof(ulong), new UlongFactory() as IPrimitiveFactory<T> },
             { typeof(short), new ShortFactory() as IPrimitiveFactory<T> },
             { typeof(ushort), new UshortFactory() as IPrimitiveFactory<T> },
             { typeof(object), new ObjectFactory() as IPrimitiveFactory<T> },
          };
    
          public T Create()
          {
             if (_primitiveFactories.ContainsKey(typeof(T)))
             {
                IPrimitiveFactory<T> primitiveFactory = _primitiveFactories[typeof(T)];
                return primitiveFactory.Create();
             }
    
             throw new KeyNotFoundException($"The key of type: {typeof(T)} is not found.");
          }
       }

All primitive types has their own factories which is determined by the type of the object.

Array factory:

    public class ArrayFactory<T> : IFactory<T>
       {
          public T Create()
          {
             var genericMethodInvoker = new GenericMethodInvokerUtil();
             Array array = Activator.CreateInstance(typeof(T), new object[] { RandomUtil.Instance.Next(1, 100) }) as Array;
             for (int i = 0; i < array.Length; i++)
             {
                Type arrayElementType = typeof(T).GetElementType();
                array.SetValue(genericMethodInvoker.InvokeMockObject<T>(arrayElementType), i);
             }
    
             return (T)Convert.ChangeType(array, typeof(T));
          }
       }

Collection factory

       public class CollectionFactory<T> : IFactory<T>
       {
          public T Create()
          {
             ICollectionFactory<T> factory = null;
    
             if (typeof(IDictionary).IsAssignableFrom(typeof(T)))
             {
                factory = new DictionaryFactory<T>() as ICollectionFactory<T>;
             }
             else if (typeof(IList).IsAssignableFrom(typeof(T)))
             {
                factory = new ListFactory<T>() as ICollectionFactory<T>;
             }
    
             return factory.Create();
          }
       }

Collections are on the other hand are separated in tow Dictionary and List

    public class DictionaryFactory<T> : ICollectionFactory<T>
       {
          public T Create()
          {
             GenericMethodInvokerUtil methodInvoker = new GenericMethodInvokerUtil();
             IDictionary dictionary = (IDictionary)Activator.CreateInstance(typeof(T));
             int numberOfElements = RandomUtil.Instance.Next(1, 100);
    
             Type[] arguments = dictionary.GetType().GetGenericArguments();
             Type keyType = arguments[0];
             Type valueType = arguments[1];
    
             for (int i = 0; i < numberOfElements; i++)
             {
                object key = methodInvoker.InvokeMockObject<object>(keyType);
                object value = methodInvoker.InvokeMockObject<object>(valueType);
    
                if (!dictionary.Contains(key))
                {
                   dictionary.Add(key, value);
                }
             }
    
             return (T)dictionary;
          }
       }

And List factory

    public class ListFactory<T> : ICollectionFactory<T>
       {
          public T Create()
          {
             GenericMethodInvokerUtil methodInvoker = new GenericMethodInvokerUtil();
             IList list = (IList)Activator.CreateInstance(typeof(T));
    
             int numberOfElements = RandomUtil.Instance.Next(1, 100);
             Type valueType = list.GetType().GetGenericArguments()[0];
    
             for (int i = 0; i < numberOfElements; i++)
             {
                object value = methodInvoker.InvokeMockObject<object>(valueType);
                list.Add(value);
             }
    
             return (T)list;
          }
       }

I am using the above code as follows:

      static void Main(string[] args)
      {
         Mocker mocker = new Mocker();
         var mock = mocker.MockObject<Test>();
      }

With Test being some class with properties.

Mock object gets called recursively from the following utility class:

       public class GenericMethodInvokerUtil
       {
          public object InvokeMockObject<T>(Type type, PropertyInfo property, object currentObject)
          {
             object concreteResult = GetMockObjectResult(type);
             property.SetValue(currentObject, concreteResult);
    
             return currentObject;
          }
    
          public object InvokeMockObject<T>(Type type)
          {
             object concreteResult = GetMockObjectResult(type);
             return concreteResult;
          }
    
          private object GetMockObjectResult(Type type)
          {
             MethodInfo method = typeof(Mocker).GetMethod("MockObject", new Type[0] { });
             MethodInfo generic = method.MakeGenericMethod(type);
    
             object instance = Activator.CreateInstance(typeof(Mocker));
             object result = generic.Invoke(instance, null);
             object concreteResult = Convert.ChangeType(result, type);
    
             return concreteResult;
          }
       }

Can anyone suggest how to write this better?

Maybe there is a pattern that I am not familiar with. 
Any help would be appreciated.

You can find the complete source of the project in my github [HERE][1].


  [1]: https://github.com/hasan-hasanov/AutoMocker