I have two storages. The first is simple. The second add additional info to entity (meta). I want to write factory that create storage based on generic type of my entity. But i can't do it. I received a compilation error. Maybe i want some weird things and i should rewrite architecture. Also i tried to use reflection, but it also didn't work. Here is an example:
using System;
using System.Reflection;
namespace ConsoleApp5
{
interface IStorage<T>
{
void Save();
}
class Storage<T> : IStorage<T>
{
public virtual void Save()
{
Console.WriteLine("Save");
}
}
class StorageWithMeta<T> : Storage<T> where T : EntityWithMeta
{
public override void Save()
{
Console.WriteLine("Save With Meta");
}
}
abstract class EntityWithMeta
{
}
class StorageFactory
{
public static IStorage<T> Create<T>()
{
if (typeof(EntityWithMeta).IsAssignableFrom(typeof(T)))
{
return CreateWithMeta<T>(); //compilation error! (type T must be convertible to EntityWithMeta)
//reflection based approach:
//var methodInfo = typeof(StorageFactory).GetMethod("CreateWithMeta", BindingFlags.Static | BindingFlags.NonPublic);
//return (IStorage<T>) methodInfo.Invoke(null, null); //System.InvalidOperationException. ContainsGenericParameters is true
}
return new Storage<T>();
}
private static IStorage<T> CreateWithMeta<T>() where T : EntityWithMeta
{
return new StorageWithMeta<T>();
}
}
class MyClass1
{
}
class MyClass2 : EntityWithMeta
{
}
class EntryPoint
{
public static void Main()
{
StorageFactory.Create<MyClass1>().Save();//expected Save
StorageFactory.Create<MyClass2>().Save();//expected Save With Meta
}
}
}
where T : EntityWithMetatoCreate<T>does not solve your problem?StorageFactory.Create<MyClass1>().Save();becauseMyClass1does not derive fromEntityWithMeta.Activator.CreateInstanceto create an instance of the generic type. The compiler cannot guarantee that your T is assignable to EntityWithMeta (it knows not about your runtime check) which is why you get the messageActivator.CreateInstance<StorageWithMeta<T>>()but if the compiler barks at that too (can't recall if it does but I think it might) then(IStorage<T>)Activator.CreateInstance(typeof(StorageWithMeta<>).MakeGenericType(new[]{typeof(T)}))