简体   繁体   English

C#泛型类使用引用类型和可空值类型

[英]C# generic class using reference types and nullable value types

I have an interesting problem. 我有一个有趣的问题。 I'd like to create a generic class that can deal with both Reference types as well as Nullable<T> types. 我想创建一个可以处理Reference类型和Nullable<T>类型的泛型类。 Basically I want something like: 基本上我想要的东西:

public class ClassWithNull<T>
{
    public T varName = null;
}

Now this, of course, does not compile because not all types can be assigned null, namely non-nullable value types. 当然,这当然不会编译,因为并非所有类型都可以赋值为null,即不可为空的值类型。 But the problem is Nullable<T> is a value type, so simply adding where T : class doesn't help me. 但问题是Nullable<T>是一个值类型,所以简单地添加where T : class对我没有帮助。 My generics-foo is not too strong, but I haven't been able to find any way to say that T must either be a reference type or a nullable value type. 我的泛型foo不是太强,但我无法找到任何方式来说T必须是引用类型或可以为值的类型。

The idea I have to solve this is to make ClassWithNull<T> an abstract class. 我必须解决的想法是使ClassWithNull<T>成为一个抽象类。 I could then add two sub-classes, one to deal with reference types and one to deal with nullable value types. 然后我可以添加两个子类,一个用于处理引用类型,另一个用于处理可空值类型。 Then, a static factory method in the base class could use reflection to determine which sub-class ought to be constructed. 然后,基类中的静态工厂方法可以使用反射来确定应该构造哪个子类。 Something like: 就像是:

public static ClassWithNull<T> CreateClassWithNull<T>()
{
    StackTrace st = new StackTrace();
    Type type = st.GetFrame(1).GetMethod().GetGenericArguments()[0];
    if (!type.IsValueType)
    {
        return new ClassWithReferenceType<T>();
    }
    else if (type == typeof(Nullable))
    {
        return new ClassWithNullableValueType<T>();
    }
    else
    {
        throw new Exception("Must provide nullable type.");
    }
}

The problem here is that generics are resolved statically. 这里的问题是泛型是静态解决的。 If ClassWithReferenceType<U> expects U to be a reference type, then calling new ClassWithReferenceType<T>() in the factory method is a compilation error since T is not required to be a reference type. 如果ClassWithReferenceType<U>期望U是引用类型,则在factory方法中调用new ClassWithReferenceType<T>()是编译错误,因为T不需要是引用类型。 The compiler does not know about the run time check. 编译器不知道运行时检查。

Any ideas about how to implement such a thing? 关于如何实现这样的事情的任何想法?

How about: 怎么样:

public class ClassWithNull<T>
{
    public T varName = default(T);
}

(Actually, you don't even need the assignment - you can just leave it to be the default value on construction. But you might want default(T) for local variables.) (实际上,你甚至不需要赋值 - 你可以将它保留为构造的默认值。但你可能想要局部变量的default(T) 。)

That won't stop you from using it incorrectly with a non-nullable value type - but is that enough? 这不会阻止您使用不可为空的值类型错误地使用它 - 但这样就够了吗?

If that doesn't help you, I would suggest writing two static methods, like this: 如果这对你没有帮助,我建议写两个静态方法,如下所示:

public static ClassWithNull<T> CreateClassWithNullForClass<T> where T : class
{
    return new ClassWithReferenceType<T>();
}

public static ClassWithNull<T> CreateClassWithNullForNullable<T> where T : struct
{
    return new ClassWithNullableValueType<T>();
}

The field in ClassWithNullableValueType would be Nullable<T> - T would be the underlying type. ClassWithNullableValueType的字段将为Nullable<T> - T将是基础类型。

Now if you want overloads of the same method, that gets a little harder, particularly if you don't want to pass any parameters. 现在,如果你想要相同方法的重载,那就会变得更难,特别是如果你不想传递任何参数。 It's possible , but really, really horrible . 这是可能的 ,但实际上,真的非常可怕

You should be able to do this instead: 您应该能够这样做:

public class ClassWithNull<T>
{
    private object varName_priv = null;

    public T varName {
        get { return (T)varName_priv; }
        set { varName_priv = value; }
    }
}

This works because every non-pointer type in C# is convertible to object , including value types. 这是有效的,因为C#中的每个非指针类型都可以转换为object ,包括值类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM