我对T有以下问题,并且通用方法的选项将其限制为例如引用类型(其中T:class)。所以我得到了以下代码:
public void mySave<T>(string filename, T obj)
{
Session s = connect(filename);
s.Save(obj);
}
与
public Document Save<TEntity>(TEntity entity) where TEntity : class;
无法声明mySave where T : class
,因为我是从界面获取的。无论如何,我需要解决CS0452 (The type 'type name' must be a reference type in order to use it as parameter 'parameter name' in the generic type or method 'identifier of generic')
关于这样做的任何想法?
答案 0 :(得分:2)
如果某个泛型参数有一些约束,那么用作参数的任何其他泛型参数必须至少提供相同的类型保证。
由于泛型是编译时的特性,可以想象Save<TEntity>
需要TEntity
作为引用类型,并且您可以给出一个可能是也可能不是值类型的参数。这会破坏仿制药的目的。
最好的办法是将整个通用约束(即T : class
)添加到界面中。
答案 1 :(得分:1)
Sriram建议两种方式......更正确的方式(由MatíasFidemraizer探索)是改变界面。另一种方式是通过反思。我完全支持MatíasFidemraizer探索的方式,并认为这是“正确的”方式。但有时你不能做正确的事情,你必须做有效的事情。
这是通过反思的另一种方式。请注意,此代码超出了必要的范围,缓存了委托,以便使用相同T
类型的其他调用不需要重用反射,并且会更快。
public static class SessionHelper
{
public static void Save2<T>(this Session session, T obj)
{
SessionHelperImpl<T>.Save(session, obj);
}
private static class SessionHelperImpl<T>
{
public static readonly Action<Session, T> Save;
static SessionHelperImpl()
{
MethodInfo saveT = (from x in typeof(Session).GetMethods()
where x.Name == "Save" && x.IsGenericMethod
let genericArguments = x.GetGenericArguments()
where genericArguments.Length == 1
let parameters = x.GetParameters()
where parameters.Length == 1 && parameters[0].ParameterType == genericArguments[0]
select x).Single();
MethodInfo save = saveT.MakeGenericMethod(typeof(T));
Save = (Action<Session, T>)save.CreateDelegate(typeof(Action<Session, T>));
}
}
}
使用它像:
s.Save2(obj);
请注意,如果您尝试将非引荐类型作为obj
传递,则会获得TypeInitializationException
。你无法真正绕过where T : class
的{{1}}。您只能在编译期间绕过它并将其延迟到运行时。