强制 T 作为代码中的引用类型 [CS0452 错误]
Force T as reference type in code [CS0452 Error]
我有以下关于 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')
有什么想法吗?
如果某些泛型参数有一些约束,用作参数的任何其他泛型参数必须至少提供相同类型的保证。
由于泛型是一个编译时特性,想象一下 Save<TEntity>
要求 TEntity
是一个引用类型,并且您可以给出一个可能是也可能不是值类型的参数。这将破坏泛型的目的。
您最好的选择是将整个通用约束(即 T : class
)也添加到界面中。
Sriram 建议了两种方法...更正确的方法(由 Matías Fidemraizer 探索)是更改界面。另一种方式是通过反射。我完全支持Matías Fidemraizer探索的方式,认为是"right"方式。但有时你不能做正确的事,你必须做有效的事。
这是另一种方式,通过反射。请注意,此代码比必要的更进一步,缓存委托以便使用相同 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
。您无法真正绕过 Save
的 where T : class
。只能在编译时绕过它,延迟到运行时。
这是我一直在寻找的答案,摘自 post:
How can I use interface as a C# generic type constraint?
where T : class, IProfile, new()
我有以下关于 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')
有什么想法吗?
如果某些泛型参数有一些约束,用作参数的任何其他泛型参数必须至少提供相同类型的保证。
由于泛型是一个编译时特性,想象一下 Save<TEntity>
要求 TEntity
是一个引用类型,并且您可以给出一个可能是也可能不是值类型的参数。这将破坏泛型的目的。
您最好的选择是将整个通用约束(即 T : class
)也添加到界面中。
Sriram 建议了两种方法...更正确的方法(由 Matías Fidemraizer 探索)是更改界面。另一种方式是通过反射。我完全支持Matías Fidemraizer探索的方式,认为是"right"方式。但有时你不能做正确的事,你必须做有效的事。
这是另一种方式,通过反射。请注意,此代码比必要的更进一步,缓存委托以便使用相同 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
。您无法真正绕过 Save
的 where T : class
。只能在编译时绕过它,延迟到运行时。
这是我一直在寻找的答案,摘自 post: How can I use interface as a C# generic type constraint?
where T : class, IProfile, new()