Pregunta

Sección 6.1 conversiones implícitas define un conversión identidad así:

una conversos de conversión identidad de cualquier tipo al mismo tipo. existe tal Esta conversión que una entidad que ya tiene un tipo requerido se puede decir que sea convertible a ese tipo.

Ahora, ¿cuál es el propósito de frases como éstas?

(En §6.1.6 conversiones referencia implícita)

Las conversiones referencia implícita son:

  • [...]
  • Desde cualquier referencia de tipo a referencia de tipo T si tiene una identidad o una referencia implícita conversión a un referencia de tipo T 0 y T 0 tiene una conversión de identidad a T.

y

(En las conversiones de boxeo §6.1.7)

  • un tipo de valor tiene una conversión de boxeo a un I tipo de interfaz si tiene una conversión de boxeo a un I tipo de interfaz 0 y I 0 tiene una conversión de identidad a I .

Inicialmente parece redundante (tautología). Pero tienen que estar allí para un propósito, ¿por qué están ahí?

¿Puede dar un ejemplo de dos tipos T 1 , T 2 tal que T 1 haría no sea convertir implícitamente a T 2 si no fuera por los párrafos más arriba citados-?

¿Fue útil?

Solución

Sección 4.7 de las notas de especificación que hay una conversión identidad de Foo<dynamic> a Foo<object> y viceversa. La parte de la especificación que usted ha citado está escrito para asegurar que este caso se maneja. Es decir, si hay una conversión de referencia implícita de T a C<object, object> entonces hay también una conversión de referencia implícita a C<object, dynamic>, C<dynamic, object> y C<dynamic, dynamic>.

Uno razonablemente podría señalar que (1) la intención de estas frases es no evidente - de ahí su pregunta - y confuso, y (2) que la sección sobre las conversiones de identidad debe hacer una referencia cruzada de la sección sobre las conversiones dinámicas, y ( 3) frases como esta en la composición de especificaciones que sea difícil para un implementador de la especificación clara traducir el lenguaje de especificaciones en una aplicación. ¿Cómo se puede saber si existe cualquier tipo? La necesidad de especificaciones no especifica los algoritmos exactos, pero sería bueno si dio más orientación.

La especificación es, por desgracia, no es un documento perfecto.

Otros consejos

Actualizar el 22-Sep-2010:

Me nadie duda va a leer esto, además de Timwi. Aun así, quería hacer algunas modificaciones a esta respuesta a la luz del hecho de que una nueva respuesta ahora ha sido aceptada y el debate aún continúa (por lo menos en mi mundo tal vez imaginaria) sobre si los fragmentos citados de la especificación son técnicamente redundante. No estoy añadiendo mucho, pero es demasiado importante como para caber en un comentario. La mayor parte de la actualización se puede encontrar bajo el título "La conversión implica el tipo dynamic" a continuación.


Actualizar el 19-Sep-2010:

En su comentario:

[E] sta no tiene sentido.

Maldición, Timwi, usted dice que mucho . Pero bien, entonces; que me has puesto a la defensiva, así que aquí va!

exención de responsabilidad: He definitivamente no examinado la especificación tan de cerca como usted tiene. Sobre la base de algunas de sus preguntas recientes parece que usted ha estado buscando en él un poco últimamente. Esto es, naturalmente, va a hacer más familiarizados con una gran cantidad de detalles que la mayoría de los usuarios de SO; por lo que este, como la mayoría de las respuestas es muy probable que recibir de nadie que no sea Eric Lippert, puede que no le satisface.

premisas diferentes

En primer lugar, la premisa de su pregunta es que si las declaraciones son resaltados redundante , entonces no cumplan ya una objetivo . La premisa de que mi respuesta es que las declaraciones redundantes no son necesariamente sin efecto cuando se aclaran algo que no es obvio para todos . Estas son las premisas contradictorias. Y si no podemos estar de acuerdo en el mismo recinto, que no podemos tener un argumento lógico sencillo. Yo simplemente estaba pidiendo que reconsiderar su premisa.

Su respuesta, sin embargo, fue a reiteran su premisa: "Si las frases son realmente redundante, entonces sólo confunden al lector y no aclaran nada"

(me gusta cómo uno se fija como representante para todos los lectores de la especificación existe, por cierto.)

No puedo culparte por mantener esta posición, exactamente. Quiero decir, sí parece obvia. Y no me dan ningún ejemplo concreto en mi respuesta original. Así que a continuación voy a tratar de incluir algunos ejemplos concretos. Pero en primer lugar, permítanme tomar un paso hacia atrás y ofrecer mi opinión sobre por qué este extraño conversión de identidad existe concepto en la especificación en el primer lugar.

El propósito de la conversión de identidad Definición

A primera vista, esta definición parece más bien una función; No se trata sólo de decir que una instancia de cualquier tipo T es convertible a ... bueno, a T? Sí lo es. Pero Mi hipótesis * que el propósito de esta definición es proporcionar la especificación con el vocabulario adecuado para utilizar el concepto de tipo de identidad en el contexto de la discusión conversiones .

Esto permite afirmaciones acerca de las conversiones que son esencialmente de naturaleza transitiva. El primer punto que citó de la especificación como un ejemplo de una declaración tautológica entra en esta categoría. Se dice que si una conversión implícita se define de algún tipo (lo llamaré K) a otro tipo T 0 y T 0 tiene una conversión a la identidad T, entonces K es implícitamente convertible a T. Por la definición de conversión identidad dada anteriormente, "tiene una conversión de identidad a" significa en realidad "es del mismo tipo que". Por lo que la declaración es redundante .

Pero de nuevo: el conversión de identidad existe definición en el primer lugar de dotar a la especificación con un lenguaje formal para describir conversiones sin tener que decir cosas como "si T < sub> 0 y T son realmente del mismo tipo. "

OK, hora de ejemplos concretos.

¿Dónde la existencia de una conversión implícita podría no ser obvio a algunos desarrolladores

Nota: Un mucho mejor ejemplo ha sido proporcionada por Eric Lippert en su respuesta a la pregunta . Les dejo estos dos primeros ejemplos como refuerzos sólo pequeñas de mi punto. También he añadido un tercer ejemplo que concretiza la conversión identidad que existe entre object y dynamic como se ha señalado en la respuesta de Eric.

Transitive Conversión de referencia

Vamos a decir que tiene dos tipos, M y N, y tienes una conversión implícita se define así:

public static implicit operator M(N n);

A continuación, el código se puede escribir así:

N n = new N();
M m = n;

Ahora digamos que usted tiene un archivo con esta declaración using encima de la tapa:

using K = M;

Y entonces usted tiene, más adelante en el archivo:

N n = new N();
K k = n;

OK, antes de continuar, me di cuenta que Esto es obvio a y . Pero mi respuesta es, y ha sido desde al principio, que podría no será obvio para todos , y por lo tanto especificando que - mientras que redundante - todavía tiene un propósito .

Eso objetivo es: dejar en claro a cualquiera que rascarse su cabeza, mirando a ese código, es legal. Un conversión implícita existe de N a M, y un conversión identidad existe de M a K (es decir, M y K son del mismo tipo); así existe una conversión implícita de N a K. No es solo lógico (aunque puede ser lógico); es justo ahí en la especificación . De lo contrario se podría erróneamente creen que algo como lo siguiente sería necesaria:

K k = (M)n;

Está claro que no lo es.

transitiva boxeo conversión

o tomar el tipo int. Un int puede ser encajonado como un IComparable<int>, ¿verdad? Así que esto es legal:

int i = 10;
IComparable<int> x = i;

Ahora considere esto:

int i = 10;
IComparable<System.Int32> x = i;

Una vez más, , puede ser obvia a usted, yo, y el 90% de todos los desarrolladores que jamás podrían venir a través de ella. Pero para que Slim minoría que no lo ve de inmediato: un conversión de boxeo existe desde int a IComparable<int>, y un conversión de identidad existe desde IComparable<int> a IComparable<System.Int32> (es decir, IComparable<int> y IComparable<System.Int32> son del mismo tipo); por lo que existe una conversión de boxeo de int a IComparable<System.Int32>.

Conversión que implica el tipo dynamic

Me voy a tomar prestado de mi ejemplo de conversión de referencia anterior y simplemente ajustar un poco para ilustrar la relación de identidad entre object y dynamic en la versión 4.0 de la especificación.

Digamos que tenemos el M<T> tipos y N, y hemos definido en algún lugar de la siguiente conversión implícita:

public static implicit operator M<object>(N n);

A continuación, la siguiente es legal:

N n = new N();
M<dynamic> m = n;

Evidentemente, lo anterior es mucho menos obvias de los dos ejemplos anteriores. Pero aquí es la pregunta del millón:? sería lo anterior Todavía ser legal incluso si no existieran los extractos de la especificación citada en la pregunta (Voy a la llamada estos extractos Q para abreviar.) Si la respuesta es sí, entonces Q es, de hecho redundante. Si no, entonces no lo es.

Creo que la respuesta es sí.

Tenga en cuenta la definición de conversión de identidad , que se define en la sección 6.1.1 (Estoy incluyendo la sección completa aquí, ya que es bastante corto):

una conversos de conversión identidad de cualquier tipo al mismo tipo. existe tal Esta conversión que una entidad que ya tiene un tipo requerido se puede decir que sea convertible a ese tipo.

Debido a equi object y dynamic se consideranvalente hay una conversión identidad entre object y dynamic, y entre los tipos construidos que son los mismos cuando se reemplaza todas las apariciones de dynamic con object . [el énfasis es mío]

(Esta última parte también se incluye en la sección 4.7, que define el tipo dynamic.)

Ahora vamos a ver el código de nuevo. En particular me interesa en esta primera línea:

M<dynamic> m = n;

La legalidad de esta declaración (sin tener en cuenta Q - recuerde, el tema que se discute es la legalidad de la hipotética declaración anterior si Q hizo no existen), ya que M<T> y N son tipos personalizados, depende de la existencia de una conversión implícita definida por el usuario entre N y M<dynamic>.

No existe una conversión implícita de N a M<object>. Por la sección de la especificación citada más arriba, hay una identidad entre la conversión y M<object> M<dynamic>. Por la definición de conversión de identidad , M<object> y M<dynamic> son del mismo tipo .

Así que, al igual que en los primeros dos ejemplos (más obvios), creo que es cierto que existe una conversión implícita de N a M<dynamic> incluso sin tener Q en cuenta , al igual que es cierto que existe una conversión implícita de N a K en el primer ejemplo y que existe una conversión de boxeo de int a IComparable<System.Int32> en el segundo ejemplo.

Sin Q , esto es mucho menos evidente (de ahí Q 's existencia); pero eso no significa que sea falsa (es decir, Q no necesaria para este comportamiento que se defina). Simplemente hace que sea menos evidente.

Conclusión

dije en mi respuesta original que esta es la explicación "obvia", porque me parecía que estaba ladrando al árbol equivocado. En un inicio se plantearon la siguiente desafío:

¿Puede dar un ejemplo de dos tipos T 1 , T 2 tal que T 1 no sería convertir implícitamente a T 2 si no fuera por los párrafos más arriba citados-?

Nadie va a responder a este desafío, Timwi, porque es imposible. Tome el primer extracto de las conversiones de referencia. Se dice que un tipo K es implícitamente convertible a un tipo T si es implícitamente convertible a T 0 y T 0 es el mismo que T. Deconstruct esto, ponerlo de nuevo juntos, y uno se queda con una tautología evidente: K es convertir implícitamente a T si se trata de convertir implícitamente a T. ¿este introducir nuevas conversiones implícitas? Por supuesto que no.

Así que tal vez el comentario de Ben Voigt era correcta; Tal vez estos puntos que usted está preguntando sobre hubiera sido mejor colocado en las notas al pie, en lugar de en el cuerpo del texto. En cualquier caso, está claro para mí que son redundante, y así comenzar con la premisa de No pueden ser redundantes, o de lo contrario no estaría allí es embarcarse en una misión inútil. Estar dispuesto a aceptar que una declaración redundante aún puede arrojar algo de luz sobre un concepto que puede no ser evidente para todos, y llegará a ser más fácil de aceptar estas declaraciones como lo que son.

redundante? Si. Tautología? Si. ¿Inútil? En mi opinión, no.

* Obviamente, yo no tenía ningún papel en la escritura de la especificación del lenguaje C #. Si lo hiciera, esta respuesta sería mucho más autorizada. Como es, simplemente representa débil intento de un individuo a tener sentido de un documento bastante complejo.


Respuesta original

Pienso que usted es (tal vez intencionalmente) con vistas a la respuesta más obvia aquí.

Tenga en cuenta estas dos frases en su pregunta:

(1) En un principio parecen redundantes (Tautología). (2) Pero tienen que estar allí para un propósito, ¿por qué están ahí?

Para mí, la implicación de estas dos frases juntas es que una afirmación tautológica no sirve para nada. Pero sólo porque una declaración es consecuencia lógica de premisas establecidas, que no lo hace obvio para todos. En otras palabras, incluso si (1) es cierto, la respuesta a (2) puede ser simplemente: para hacer que el comportamiento descrito claro para cualquiera que lea la especificación .

Ahora se podría argumentar que incluso si algo no es obvia , que todavía no tiene cabida en una especificación de si se está proporcionando una definición redundante. A esta objeción potencial, sólo puedo decir: sea realista. En realidad no es práctico (en mi opinión) de peinar a través de un documento excluyendo todas las declaraciones que son simplemente indicando los hechos que podrían haber sido deducidos de las declaraciones anteriores.

Si esto estaban una práctica común, creo que iba a encontrar una gran cantidad de literatura por ahí - no sólo características, pero los trabajos de investigación, artículos, libros de texto, etc. - sería una mucho más corto, más denso y más difícil de entender.

Así que: sí, tal vez, que son redundantes. Pero eso no niega su propósito.

una conversos de conversión identidad desde cualquier tipo al mismo tipo . Esta existe conversión tal que una entidad que ya tiene un tipo requerido lata decirse que es convertible a ese tipo.

Esto dice que en C # Land, 1 == 1; una espada es una espada. Esta es la base de la asignación de una referencia de objeto a una variable del mismo tipo; Si una variable de tipo T1 y T2 son uno escrito en realidad, ambas espadas, es posible asignar uno a otro sin tener que emitir un explícitamente como una espada. Imagine una variante C #, donde las tareas tenían que tener este aspecto:

Spade mySpade = new Spade();
Spade mySpade2;

mySpade2 = (Spade)mySpade; //explicit cast required

Además, una "identidad" en matemáticas establece que una expresión que se evalúa como un resultado dado un conjunto de entradas es equivalente a otra expresión que produce el mismo resultado dado las mismas entradas. En la programación, esto significa que una expresión o función que se evalúa como una instancia de un tipo es equivalente a ese tipo, sin conversión explícita. Si eso no se sostiene, se requiere el siguiente código:

public int myMethod() { /*Do something*/ }
...
int myInt = (int)myMethod(); //required even though myMethod() evals to an int.
...
int myInt = (int)(1 + 2); //required even though 1, 2, and 1+2 eval to an int.

La segunda regla básicamente dice que un tipo de valor se puede asignar a una variable miembro de una clase si, en parte, la variable miembro (un tipo de caja, por definición, como su contenedor es un tipo de referencia) se declara a ser el el mismo tipo. Si esta regla no se especificaron, en teoría, una versión de C # podría existir en la que los tipos de valores puros tendrían que ser convertidos de forma explícita a su análogo de referencia con el fin de ser almacenado como una variable miembro de una clase. Imaginemos, por ejemplo, una versión de C # en el que los tipos azul de palabras clave (int, float, decimales) y los nombres de la luz azul de la clase (Int32, flotador, decimal) se refirió a dos muy diferentes, sólo los tipos-explícitamente convertibles, e int , flotador, decimales, etc., no eran legales como miembro de los tipos de variables, ya que no eran los tipos de referencia:

public class MyClass
{
  Int32 MyBoxedValueType; //using "int" not legal
}

...

MyClass myClass = new MyClass();
int theInt = 2;

myClass.MyBoxedValueType = (Int32)theInt; //explicit cast required

Sé que suena tonto, pero en algún nivel, estas cosas deben ser conocidos, y en las computadoras, hay que especificar TODO. Leer el libro de reglas EE.UU. Hockey para algún momento de hockey sobre hielo; la primera regla en el libro es que el juego se juega en una superficie de hielo. Es una de las últimas "así DUHS", sino también una verdad fundamental del juego que debe ser entendido con el fin de cualquier otra norma a tener sentido.

Mayo es tal que las garantías de código de paso a través de cuando se le llama como Convert.ChangeType(client, typeof(Client)) sin tener en cuenta si se implementa IConvertible.

Look en la fuente de ChangeType de mscorlib con reflector y observe las condiciones en que se devuelve value como está.

Recuerde que un operador = no es una conversión, a un conjunto de referencia. Por lo tanto el código como Client client_2 = client_1 no realiza ninguna conversión implícitas. Si se declara una conversión implícita identidad entonces error CS0555 se emite.

Creo que la especificación dice que le permita a los compilador de C # manejar estos casos, y por lo tanto DOT No tratan manualmente para definir las conversiones de identidad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top