C# 有没有办法把这些几乎相同的类合并成一个类?
本问题的后续行动: 我有两个类,它们基本上是用一个内部对象维护用户提供的值的元组 当用户提供的值的类型是原语时,我必须将其包装在C# 有没有办法把这些几乎相同的类合并成一个类?,c#,generics,nullable,type-constraints,C#,Generics,Nullable,Type Constraints,本问题的后续行动: 我有两个类,它们基本上是用一个内部对象维护用户提供的值的元组 当用户提供的值的类型是原语时,我必须将其包装在Nullable中,以便它可以在元组中接受null值 public class BundledClass<T> where T : class { private Tuple<T, object> _bundle; public T Value { get { return _bundle == null
Nullable
中,以便它可以在元组中接受null值
public class BundledClass<T> where T : class
{
private Tuple<T, object> _bundle;
public T Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
//...
public class BundledPrimitive<T> where T : struct
{
private Tuple<T?, object> _bundle;
public T? Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T?, object>(value, internalObj); }
}
//...
但即使这样也会失败,因为
Nullable
不符合:class
约束(根据链接的问题)。如果您只是这样设计类:
public abstract class Bundled<T>
{
private Tuple<T, object> _bundle;
public T Value
{
get { return _bundle == null ? default(T) : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
}
public class BundledClass<T> : Bundled<T> where T : class { }
public class BundledStruct<T> : Bundled<T?> where T : struct { }
绑定的公共抽象类
{
私有元组束;
公共价值
{
获取{return _bundle==null?默认值(T):_bundle.Item1;}
set{u bundle=新元组(值,internalObj);}
}
}
然后,您可以通过将类型参数指定为可为null的来将其与结构一起使用,例如:
Bundled<string> foo; // handles classes
Bundled<float?> bar; // handles structs
Bundled foo;//处理类
捆扎钢筋;//句柄结构
这里唯一的问题是,用户可能会将此类与不可为空的结构一起使用,例如捆绑的
。如果应用程序中确实存在这一问题,则可以声明更具体的子类型,如下所示:
public abstract class Bundled<T>
{
private Tuple<T, object> _bundle;
public T Value
{
get { return _bundle == null ? default(T) : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
}
public class BundledClass<T> : Bundled<T> where T : class { }
public class BundledStruct<T> : Bundled<T?> where T : struct { }
公共类BundledClass:Bundled其中T:class{}
公共类BundledStruct:Bundled,其中T:struct{}
您还可以将
绑定的
构造函数设置为内部构造函数,这样就不能从程序集外部调用它。这将确保用户不会创建自定义子类型来绕过您的BundledClass
/BundledStruct
包装器。我刚才能想到的最好方法。它仍然是两个类,但它使我免于数百行代码重复:
public abstract class Bundled<T>
{
protected Tuple<T, object> _bundle;
public abstract T Value { get; set; }
//... Everything else
}
public class BundledClass<T> : Bundled<T> where T : class
{
public sealed override T Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
}
public class BundledPrimitive<T> : Bundled<T?> where T : struct
{
public sealed override T? Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T?, object>(value, internalObj); }
}
}
绑定的公共抽象类
{
受保护元组束;
公共抽象T值{get;set;}
//…其他一切
}
公共类BundledClass:绑定,其中T:class
{
公共密封覆盖T值
{
获取{返回_bundle==null?null:_bundle.Item1;}
set{u bundle=新元组(值,internalObj);}
}
}
公共类BundledPrimitive:绑定,其中T:struct
{
公共密封覆盖T?值
{
获取{返回_bundle==null?null:_bundle.Item1;}
set{u bundle=新元组(值,internalObj);}
}
}
无法使用默认值(t)
。如果用户创建了一个绑定的foo
,我绝对必须区分他们何时设置了foo.Value=0
和何时未设置foo.Value
(因此\u bundle=Tuple(null,internalObj)
),我想这和下面的答案一样有效,只要没有人试图在没有类型约束的情况下实现捆绑的。@Alain如我所说,您可以将构造函数设置为内部构造函数,因此只能从程序集中调用它。这意味着从捆绑的派生的任何外部类型都不会编译(至少在没有大量反射的情况下不会编译)。如果希望用户能够从公共构造函数继承,请确保BundledClass
/BundledStruct
提供公共构造函数。这可以与静态构造函数中的运行时检查相结合,以确保T
是“好的”。这是因为没有编译时泛型约束。静态构造函数应该去static Bundled(){if(typeof(T).IsValueType&&Nullable.getunderyingtype(typeof(T))==null)抛出新的invalidoOperationException(“T必须允许null”);}
您可以将这种方法与@Alain结合起来,使Bundled
抽象,而无需向其添加任何虚拟方法。这不会阻止同一程序集中的代码从中派生,但它不会像在同一程序集中一样可用,并且对于内部ctor,它将禁止任何其他程序集使用。如果我是此类的用户,如何区分未设置的值
和已在程序中的其他地方将值
设置为null的我?@mikez如果从未设置过该值,则内部\u bundle=null
。如果Value
设置为null,则内部\u bundle
将是一个元组(null,internalObj)
。这并不重要,但用户可以使用返回\u bundle
的public get-only属性看到这一点。是的,这将是内部状态的区别,但作为调用者,我无权访问\u bundle
@Alain BTW,我在回答中选择了名称BundledStruct
而不是BundledPrimitive
,因为两者并不完全相同。DateTime
是一个结构,但不是基元,string
是C#中的基元(尽管Type.IsPrimitive
将返回false),但它不是一个结构。