restrict - where generic type constraint c#




O que exatamente é uma "classe especial"? (5)

Conforme a especificação de idioma do C # 4.0 (codificada: [10.1.5] restrições de parâmetro de tipo) informa duas coisas:

1] O tipo não deve ser objeto. Como todos os tipos derivam do objeto, essa restrição não teria efeito se fosse permitida.

2] Se T não possui restrições primárias ou restrições de parâmetro de tipo, sua classe base efetiva é objeto.

Ao definir uma classe genérica, você pode aplicar restrições aos tipos de tipos que o código do cliente pode usar para argumentos de tipo quando instancia sua classe. Se o código do cliente tentar instanciar sua classe usando um tipo que não é permitido por uma restrição, o resultado será um erro em tempo de compilação. Essas restrições são chamadas de restrições. As restrições são especificadas usando a palavra-chave contextual where. Se você deseja restringir um tipo genérico a um tipo de referência, use: class.

public class Gen<T> where T : class
{
}

Isso proibirá o tipo genérico de ser um tipo de valor, como int ou struct, etc.

Além disso, a restrição não pode ser uma classe especial 'identificador'. Os seguintes tipos não podem ser usados ​​como restrições:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

Depois de não conseguir obter algo como o seguinte para compilar:

public class Gen<T> where T : System.Array
{
}

com o erro

Uma restrição não pode ser da classe especial `System.Array '

Comecei a me perguntar, o que exatamente é uma "classe especial"?

As pessoas geralmente parecem ter o mesmo tipo de erro quando especificam System.Enum em uma restrição genérica. System.ValueType os mesmos resultados com System.Object , System.Delegate , System.MulticastDelegate e System.ValueType também.

Existem mais deles? Não consigo encontrar nenhuma informação sobre "classes especiais" em C #.

Além disso, o que há de tão especial nessas classes que não podemos usá-las como uma restrição de tipo genérico?


De acordo com o MSDN , é uma lista estática de classes:

Erro do compilador CS0702

A restrição não pode ser uma classe especial 'identificador' Os seguintes tipos não podem ser usados ​​como restrições:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

Eu não acho que exista alguma definição oficial de "classes especiais" / "tipos especiais".

Você pode pensar neles tipos, que não podem ser usados ​​com semântica de tipos "regulares":

  • você não pode instancia-los diretamente;
  • você não pode herdar deles o tipo personalizado diretamente;
  • existe alguma mágica do compilador para trabalhar com eles (opcionalmente);
  • o uso direto de suas instâncias pelo menos inútil (opcionalmente; imagine que você criou genérico acima, que código genérico você escreverá?)

PS: Eu adicionaria System.Void à lista.


Existem certas classes no Framework que efetivamente transmitem características especiais a todos os tipos derivados, mas não possuem essas características . O próprio CLR não impõe nenhuma proibição contra o uso dessas classes como restrições, mas tipos genéricos restritos a elas não adquirem as características não herdadas da mesma forma que os tipos concretos. Os criadores do C # decidiram que, como esse comportamento pode confundir algumas pessoas e eles não conseguiram ser úteis, deveriam proibir essas restrições em vez de permitir que se comportassem como no CLR.

Se, por exemplo, fosse permitido escrever: void CopyArray<T>(T dest, T source, int start, int count) ; seria possível passar dest e source para métodos que esperam um argumento do tipo System.Array ; além disso, obteríamos uma validação em tempo de compilação de que dest e source eram os tipos de matriz compatíveis, mas não seria possível acessar elementos da matriz usando o operador [] .

A incapacidade de usar Array como uma restrição é bastante fácil de contornar, pois o void CopyArray<T>(T[] dest, T[] source, int start, int count) funcionará em quase todas as situações em que o método anterior funcionaria. trabalhos. No entanto, ele tem um ponto fraco: o método anterior funcionaria no cenário em que um ou os dois argumentos fossem do tipo System.Array enquanto rejeitava casos em que os argumentos são tipos de matriz incompatíveis; adicionando uma sobrecarga em que ambos os argumentos eram do tipo System.Array faria o código aceitar os casos adicionais que deveria aceitar, mas também aceitaria erroneamente casos que não deveria.

Acho que a decisão de proibir a maioria das restrições especiais é cansativa. O único que teria zero significado semântico seria System.Object [desde que isso fosse legal como restrição, qualquer coisa o satisfaria]. System.ValueType provavelmente não seria muito útil, uma vez que as referências do tipo ValueType realmente não têm muito em comum com os tipos de valor, mas pode plausivelmente ter algum valor nos casos que envolvem Reflexão. O System.Enum e o System.Delegate teriam alguns usos reais, mas como os criadores do C # não pensaram neles, eles são proibidos sem um bom motivo.


O seguinte pode ser encontrado no CLR via C # 4th Edition:

Restrições Primárias

Um parâmetro de tipo pode especificar zero restrições primárias ou uma restrição primária. Uma restrição primária pode ser um tipo de referência que identifica uma classe que não está selada. Você não pode especificar um dos seguintes tipos de referência especiais: System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum ou System.Void . Ao especificar uma restrição de tipo de referência, você promete ao compilador que um argumento de tipo especificado seja do mesmo tipo ou de um tipo derivado do tipo de restrição.





generic-constraints