强制 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。您无法真正绕过 Savewhere T : class。只能在编译时绕过它,延迟到运行时。

这是我一直在寻找的答案,摘自 post: How can I use interface as a C# generic type constraint?

where T : class, IProfile, new()