Então, eu tenho esta aula:
public class Foo<T> where T : ???
{
private T item;
public bool IsNull()
{
return item == null;
}
}
Agora estou procurando uma restrição de tipo que me permita usar tudo como parâmetro de tipo que possa ser null
. Isso significa todos os tipos de referência, bem como todos os tipos Nullable
( T?
):
Foo<String> ... = ...
Foo<int?> ... = ...
deve ser possível.
Usar class
como restrição de tipo apenas me permite usar os tipos de referência.
Informações Adicionais:
Estou escrevendo um aplicativo de tubos e filtros e quero usar uma null
referência como o último item que passa para o pipeline, para que cada filtro possa fechar bem, fazer limpeza, etc ...
IFoo<T>
como o tipo de trabalho e criar instâncias por meio de um método de fábrica? Isso poderia funcionar.Respostas:
Se você estiver disposto a fazer uma verificação de tempo de execução no construtor de Foo em vez de ter uma verificação de tempo de compilação, você pode verificar se o tipo não é uma referência ou tipo anulável e lançar uma exceção se for o caso.
Eu percebo que apenas ter uma verificação de tempo de execução pode ser inaceitável, mas apenas no caso:
Em seguida, o código a seguir é compilado, mas o último (
foo3
) lança uma exceção no construtor:fonte
static bool isValidType
campo que você definiu no construtor estático, então apenas verifique o sinalizador no construtor de instância e jogue se for um tipo inválido, então você não fará todo o trabalho de verificação cada vez que construir uma instância. Eu uso esse padrão com frequência.Não sei como implementar equivalente a OR em genéricos. No entanto, posso propor o uso de palavra-chave padrão a fim de criar nulo para tipos anuláveis e valor 0 para estruturas:
Você também pode implementar sua versão de Nullable:
Exemplo:
fonte
Corri para esse problema para um caso mais simples de querer um método estático genérico que pudesse tomar qualquer coisa "anulável" (tipos de referência ou Nullables), o que me trouxe a esta questão sem solução satisfatória. Então eu vim com minha própria solução que era relativamente mais fácil de resolver do que a pergunta declarada do OP, simplesmente tendo dois métodos sobrecarregados, um que leva a
T
e tem a restriçãowhere T : class
e outro que leva aT?
e temwhere T : struct
.Então percebi que essa solução também pode ser aplicada a este problema para criar uma solução que seja verificável em tempo de compilação, tornando o construtor privado (ou protegido) e usando um método de fábrica estático:
Agora podemos usá-lo assim:
Se você quiser um construtor sem parâmetros, não terá a delicadeza da sobrecarga, mas ainda pode fazer algo assim:
E use-o assim:
Existem algumas desvantagens para esta solução, uma é que você pode preferir usar 'novo' para construir objetos. Outra é que você não será capaz de usar
Foo<T>
como um argumento de tipo genérico para um tipo de restrição de algo como:where TFoo: new()
. Finalmente, está o código extra de que você precisa aqui, que aumentaria especialmente se você precisar de vários construtores sobrecarregados.fonte
Conforme mencionado, você não pode ter uma verificação em tempo de compilação para ele. Faltam restrições genéricas no .NET e não oferecem suporte à maioria dos cenários.
No entanto, considero esta a melhor solução para verificação em tempo de execução. Ele pode ser otimizado em tempo de compilação JIT, uma vez que ambos são constantes.
fonte
Essa restrição de tipo não é possível. De acordo com a documentação das restrições de tipo, não há restrição que capture os tipos anuláveis e de referência. Como as restrições só podem ser combinadas em uma conjunção, não há como criar essa restrição por combinação.
Você pode, no entanto, para suas necessidades, recorrer a um parâmetro de tipo irrestrito, uma vez que você sempre pode verificar == null. Se o tipo for um tipo de valor, a verificação sempre será avaliada como falsa. Em seguida, você possivelmente obterá o aviso R # "Possível comparação do tipo de valor com nulo", o que não é crítico, contanto que a semântica seja adequada para você.
Uma alternativa poderia ser usar
em vez da verificação de nulo, pois o padrão (T) onde T: classe é sempre nulo. Isso, entretanto, significa que você não pode distinguir se um valor não anulável nunca foi definido explicitamente ou apenas foi definido com seu valor padrão.
fonte
eu uso
fonte
fonte