para medicamentos genericos donde comprar baratos ayuda c# .net templates generics

c# - genericos - donde comprar medicamentos baratos



¿Los genéricos no pueden inferir segundo parámetro? (3)

He notado que el compilador de C # no infiere el segundo parámetro genérico.
Ejemplo:

Código de plantilla de C ++: (sí, sé que las plantillas no funcionan como los genéricos)

class Test { public: template <class T,class V> T test(V v) { //do something with v return T(); } }; int i = 0; Test t = new Test(); double j = t.test<double>(i); //infers V as int

Las plantillas (y los genéricos) no pueden inferir el tipo de retorno, por lo que en C ++ le doy el primer parámetro de plantilla, y el segundo parámetro de plantilla se deduce del tipo de variable.

Ahora, el mismo ejemplo en C #:

class Test { public T test<T,V>(V v) where T: new() { //do something with v return new T(); } }; int i = 0; Test t = new Test(); double j = t.test<double>(i); //Error Using the generic method ''Test.test<T,V>(V)'' requires ''2'' type arguments

Pero si uso 1 tipo, no tengo que especificar explícitamente el tipo:

class Test { public V test<V>(V v) where V: new() { return new V(); } }; int i = 0; Test t = new Test(); int j = t.test(i); //OK infers V as int.

Entonces, ¿por qué los genéricos de C # no pueden inferir el segundo tipo (mientras que en las plantillas de c ++ claramente puede)?
Estoy seguro de que está diseñado de esa manera (dudo que el equipo de .Net haya pasado esto por alto), entonces, ¿ por qué está diseñado de esta manera que debo especificar explícitamente ambos tipos?

Editar:

De las discusiones que tuvimos en las respuestas hasta el momento, ambos idiomas admiten la sobrecarga por el número de parámetros de la plantilla.

Así que de nuevo, ¿por qué C # está diseñado de esta manera? ¿Qué es diferente en la implementación del lenguaje que no permite declarar explícitamente solo un parámetro?


C # ha sido diseñado para ser un lenguaje un poco menos complejo que C ++.

En particular, no creo que sea una buena idea comparar los genéricos de C # con las plantillas de C ++ por varias razones: son fundamentalmente dos enfoques muy diferentes para lograr cosas similares en algunas situaciones. El enfoque de C ++ es ciertamente flexible en algunos aspectos, aunque no permite (como yo lo entiendo) plantillas que solo existen en forma binaria, o que se creen nuevas especializaciones de plantillas en el momento de la ejecución. Básicamente, el enfoque de la plantilla de C ++ no encaja bien con el resto de cómo encaja .NET.

Ahora, por qué no puede especificar algunos argumentos de tipo y permitir que se deduzcan otros (que es una decisión de lenguaje en lugar de una decisión de plataforma ; estoy seguro de que sería factible en lo que respecta a .NET en sí). Creo que esto es por simplicidad. Elegir el método correcto exacto y los argumentos de tipo correcto ya es extremadamente complicado en C #, más complicado de lo que la mayoría de los desarrolladores de C # pueden hacerles entender. Se trata de:

  • Potencialmente considerando métodos para la jerarquía de tipos del tipo en tiempo de compilación del objetivo
  • Sobrecarga por número de parámetros.
  • Sobrecarga por el número de parámetros tipo
  • El efecto de los argumentos nombrados.
  • El efecto de los parámetros opcionales.
  • El efecto de las restricciones de parámetros de tipo genérico en los tipos de parámetros ( no restricciones especificadas por el método de destino, nota)
  • Grupo de métodos para delegar conversiones.
  • Conversiones de funciones anónimas
  • Inferencia de tipo para argumentos de tipo
  • Tipificación dinámica
  • Covarianza genérica y contravarianza.

Personalmente, creo que eso es suficiente para entenderlo, sin permitir aún más posibilidades a través de "M puede ser un candidato si tiene al menos tantos parámetros de tipo como argumentos de tipo especificado". ¿También querría argumentos de tipo con nombre y parámetros de tipo opcionales? ;)

He observado la sobrecarga bastante, siguiendo las especificaciones a fondo, etc. He encontrado áreas que hacen que los diseñadores de lenguajes se esfuercen y traten de averiguar qué debe hacer el compilador. He encontrado áreas en las que el compilador definitivamente se equivoca. No me gustaría agregar más complejidad aquí sin una buena razón.

Así que sí, es básicamente por simplicidad, y a veces eso es un dolor, pero a menudo se puede evitarlo. Para cada característica potencial, debe tener en cuenta:

  • El beneficio de la característica para los desarrolladores finales.
  • El costo de la función para los desarrolladores finales en términos de tiempo dedicado a entenderlo
  • El costo para los diseñadores de idiomas en el diseño y la especificación a fondo.
  • El costo para los escritores del compilador al implementarlo correctamente.
  • El costo para el equipo de pruebas al realizar una prueba exhaustiva (junto con todo lo demás relacionado con la sobrecarga)
  • El costo de las funciones potenciales futuras (si esto hace que el lenguaje sea más complicado, eso deja menos complejidad adicional "potencialmente insuperable" para otras funciones)

Como dijo Dan, C # no le permite inferir solo algunos parámetros de tipo de un conjunto de parámetros genéricos. Es probable que esto permita la sobrecarga en función del número de parámetros genéricos (que C # permite, al menos para las clases genéricas).

Sin embargo, puede especificar parámetros de una clase genérica e inferir parámetros de un método genérico dentro de esa clase. Pero esta solución no siempre es una buena solución.


Una cosa que puede ayudar en algunos casos en los que uno desearía especificar algunos parámetros de tipo y hacer inferir otros es crear una clase estática genérica con los parámetros que se desea especificar, y luego, dentro de esa clase, tener un método estático genérico con los parámetros uno. quiere haber inferido. Por ejemplo, tengo un método que, dado un método que se puede convertir en una Acción (T, U, V), junto con una T, generará una Acción (U, V) que llamará a ese delegado con la especificación original T junto con la U y V. El método se invocaría como (sintaxis vb):

NewAction = ActionOf(Of FooType, BarType).NewAction(AddressOf MyFunctionOfBozFooBar, someBoz)

El compilador puede determinar uno de los parámetros de tipo genérico utilizando el tipo de someBoz, aunque necesita tener los parámetros FooType y BarType explícitamente especificados.