我有两个存储空间。第一个很简单。第二个向实体(meta)添加附加信息。我想编写基于我的实体的泛型类型创建存储的工厂。但我无法做到。我收到了编译错误。也许我想要一些奇怪的东西,我应该重写架构。我也尝试使用反射,但它也没有用。这是一个例子:
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
}
}
}
答案 0 :(得分:2)
问题在于,尽管运行时检查,编译器仍无法保证T
可分配给EntityWithMeta
。换句话说,它不知道if
语句在上下文中的含义。您可以使用Activator.CreateInstance和Type.MakeGenericType
return (IStorage<T>)Activator.CreateInstance(typeof(StorageWithMeta<>).MakeGenericType(typeof(T)));
关于基于反射的方法的注释(您在OP中注释掉了):方法CreateWithMeta
本身就是通用的。您拥有的MethodInfo
对象用于通用方法定义。您处于正确的轨道,但您必须使用MethodInfo.MakeGenericMethod:
var methodInfo = typeof(StorageFactory).GetMethod("CreateWithMeta", BindingFlags.Static | BindingFlags.NonPublic);
var constructedGeneric = methodInfo.MakeGenericMethod(typeof(T));
return (IStorage<T>)constructedGeneric.Invoke(null, null);