Existe alguma maneira de combinar essas classs quase idênticas em uma?

Seguimento desta pergunta: Por que o Nullable é considerado uma estrutura e não uma class?

Eu tenho duas classs que mantêm essencialmente uma tupla de algum valor fornecido pelo usuário com um object interno.

Quando o tipo do valor fornecido pelo usuário é primitivo, eu tenho que envolvê-lo em um Nullable para que ele possa assumir um valor nulo no Tuple.

 public class BundledClass where T : class { private Tuple _bundle; public T Value { get { return _bundle == null ? null : _bundle.Item1; } set { _bundle = new Tuple(value, internalObj); } } //... public class BundledPrimitive where T : struct { private Tuple _bundle; public T? Value { get { return _bundle == null ? null : _bundle.Item1; } set { _bundle = new Tuple(value, internalObj); } } //... 

Eu preferiria que pudesse fazer isso com uma única class que pudesse usar primitivas ou classs como um parâmetro de tipo, mas não vejo nenhuma maneira de contornar isso. Não sem criar algum tipo de class Nullable customizada que possa conter qualquer tipo (não apenas tipos where T:struct ) de forma a assegurar que Value sempre possa ser atribuído null;

Parece que eu deveria pelo menos ser capaz de definir a última class como

 public class BundledPrimitive : BundledClass { } 

Mas mesmo isso falha, pois Nullable não atende à restrição : class (conforme a pergunta vinculada).

Se você simplesmente projetou sua class assim:

 public abstract class Bundled { private Tuple _bundle; public T Value { get { return _bundle == null ? default(T) : _bundle.Item1; } set { _bundle = new Tuple(value, internalObj); } } } 

Então você pode usá-lo com uma estrutura especificando o parâmetro type como um Nullable , por exemplo:

 Bundled foo; // handles classs Bundled bar; // handles structs 

O único problema aqui é que é possível que um usuário possa usar essa class com uma estrutura não anulável – por exemplo, Bundled . Se isso é realmente uma preocupação em seu aplicativo, você pode declarar sub-tipos mais específicos como este:

 public class BundledClass : Bundled where T : class { } public class BundledStruct : Bundled where T : struct { } 

Você também pode tornar o construtor de Bundled interno, de modo que não possa ser chamado de fora do seu assembly. Isso garantirá que o usuário não crie um subtipo personalizado para ignorar seus wrappers BundledStruct / BundledStruct .

O melhor que consegui fazer agora. Ainda são duas classs, mas me salvam de centenas de linhas de duplicação de código:

 public abstract class Bundled { protected Tuple _bundle; public abstract T Value { get; set; } //... Everything else } public class BundledClass : Bundled where T : class { public sealed override T Value { get { return _bundle == null ? null : _bundle.Item1; } set { _bundle = new Tuple(value, internalObj); } } } public class BundledPrimitive : Bundled where T : struct { public sealed override T? Value { get { return _bundle == null ? null : _bundle.Item1; } set { _bundle = new Tuple(value, internalObj); } } }