utilizadas significa referencia que palabras lenguaje identificadores ejemplos comandos codigos claves clase c# .net dynamic boxing

referencia - que significa c#



¿Cómo probar si un valor está encuadrado en C#/.NET? (9)

GetType () e IsValueType no revelan la diferencia entre un valor enmarcado y un valor no empacado.

GetType es un método sellado (no virtual) en System.Object . Llamar a este método en un tipo de valor definitivamente lo encajonará. Ni siquiera Nullable<T> puede evitar esto: al llamar a GetType en un valor nulo devolverá el tipo subyacente si tiene un valor (encuadrado como el tipo subyacente) o arrojará una NullReferenceException si no lo hace (encerrado en nulo, puede desreferencia una referencia nula).

cuando se observa cualquier variable o valor, incluso si su tipo es "dinámico" u "objeto", ya sea que esté enmarcado o no encuadrado.

En general, si tiene una expresión que "contiene" un tipo de valor, el valor de esa expresión será una referencia a un cuadro, a menos que el tipo de tiempo de compilación de la expresión sea del mismo tipo de valor (los genéricos son un poco más complicados) . Los tipos de referencia comunes que pueden contener referencias a estructuras encuadradas son object , dynamic y tipos de interfaz.

Estoy buscando una forma de escribir código que pruebe si un valor está encasillado.

Mis investigaciones preliminares indican que .NET hace todo lo posible por ocultar el hecho, lo que significa que GetType() y IsValueType no revelan la diferencia entre un valor encasillado y un valor no empacado. Por ejemplo, en las siguientes expresiones de LinqPad C #, tengo fe en que o1 está o1 e i1 no está o1 , pero me gustaría una forma de probarlo en código o, en segundo lugar, una forma de saber SEGURO al mirar cualquier variable o valor, incluso si su tipo es "dinámico" u "objeto", ya sea que esté enmarcado o no encuadrado.

¿Algún consejo?

// boxed? -- no way to tell from these answers! object o1 = 123; o1.GetType().Dump("o1.GetType()"); o1.GetType().IsValueType.Dump("o1.GetType().IsValueType"); // not boxed? -- no way to tell from these answers! int i1 = 123; i1.GetType().Dump("i1.GetType()"); i1.GetType().IsValueType.Dump("i1.GetType().IsValueType");


Aquí hay algunos métodos simples de ayuda para verificar si una variable es un entero encuadrado:

public static bool IsBoxed(object item) { return true; } public static bool IsBoxed<T>(T item) where T : struct { return false; }

Simplemente llame a IsBoxed(...) en su variable:

IsBoxed(o1) // evaluates to true IsBoxed(i1) // evaluates to false

Esto no logra nada, por supuesto. ¿Por qué exactamente necesita saber si un valor está encasillado o no?


Bueno, usemos el truco ...

¿Qué sabemos?

  • La variable de tipo valor se coloca una y otra vez cuando se asigna a la variable de tipo de referencia
  • La variable de tipo de referencia no se encasillará de nuevo ...

Así que solo comprobaremos si se empaqueta de nuevo (en otro objeto) ... así que comparamos referencias

isReferenceType será falso aquí, porque comparamos 2 objetos en el montón (uno en caja en surelyBoxed en surelyBoxed , uno en recuadro justo en la llamada a ReferenceEquals):

int checkedVariable = 123; //any type of variable can be used here object surelyBoxed = checkedVariable; bool isReferenceType = object.ReferenceEquals(surelyBoxed, checkedVariable);

isReferenceType será verdadero aquí, porque comparamos 1 objeto en el montón a sí mismo:

object checkedVariable = 123; //any type of variable can be used here object surelyBoxed = checkedVariable; bool isReferenceType = object.ReferenceEquals(surelyBoxed, checkedVariable);

Esto funciona para CUALQUIER tipo, no solo para int y object

Para ponerlo en un método bien utilizable:

public static bool IsReferenceType<T>(T input) { object surelyBoxed = input; return object.ReferenceEquals(surelyBoxed, input); }

Este método se puede usar fácilmente así:

int i1 = 123; object o1 = 123; //... bool i1Referential = IsReferenceType(i1); //returns false bool o1Referential = IsReferenceType(o1); //returns true


Creo que en realidad la pregunta es un poco errónea. ¿No es la pregunta en realidad, "¿Cómo puedo saber si un objeto es un cuadro para otro tipo?"

Con referencia al comentario de Allon, si tiene un objeto de tipo Object y el objeto es un tipo de valor primitivo, es un cuadro. No estoy seguro de que esto sea 100% correcto, pero (similar a la implementación de Allon):

// Assume there is some object o. bool isBoxed = o.GetType().IsPrimitive;


Este enfoque es similar a la respuesta de Jared Par. Pero creo que !typeof(T).IsValueType es más limpio que enumerar todos los tipos que podrían contener un valor encuadrado.

public static bool IsBoxed<T>(T value) { return !typeof(T).IsValueType && (value != null) && value.GetType().IsValueType; }

A diferencia del código de Jared, este manejará el caso donde T es System.ValueType correctamente.

Otro punto sutil es ese value.GetType().IsValueType viene después de !typeof(T).IsValueType ya que de lo contrario GetType() crearía una copia en caja temporal del valor.


No estoy seguro de si esto será relevante para alguien, pero desde que me encontré con esta publicación, porque el boxeo realmente estaba impactando en mi asignación dinámica.

Sigil proporciona un fantástico método UnBoxAny

Suponiendo que tiene lo siguiente:

public class Report { public decimal Total { get; set; } }

new Dictionary<string, object> { { "Total", 5m} }

Entonces, el valor decimal está encuadrado.

var totalProperty = typeof(Report).GetProperty("Total"); var value = emit.DeclareLocal<object>(); //invoke TryGetValue on dictionary to populate local ''value''* //stack: [bool returned-TryGetValue] //either Pop() or use in If/Else to consume value ** //stack: //load the Report instance to the top of the stack //(or create a new Report) //stack: [report] emit.LoadLocal(value); //stack: [report] [object value] emit.UnboxAny(totalProperty.PropertyType); //stack: [report] [decimal value] //setter has signature "void (this Report, decimal)" //so it consumes two values off the stack and pushes nothing emit.CallVirtual(totalProperty.SetMethod); //stack:

* invocar TryGetValue

** uso en If / Else


Pruebe lo siguiente

public static bool IsBoxed<T>(T value) { return (typeof(T).IsInterface || typeof(T) == typeof(object)) && value != null && value.GetType().IsValueType; }

Al usar un genérico, permitimos que la función tenga en cuenta tanto el tipo de expresión como el compilador y su valor subyacente.

Console.WriteLine(IsBoxed(42)); // False Console.WriteLine(IsBoxed((object)42)); // True Console.WriteLine(IsBoxed((IComparable)42)); // True

EDITAR

Un par de personas pidieron aclaraciones sobre por qué esto tiene que ser genérico. Y cuestionó por qué esto es siquiera necesario en absoluto, ¿no puede el desarrollador solo mirar el código y decir si un valor está encasillado? En un intento de responder ambas preguntas, considere la siguiente firma de método

void Example<T>(T param1, object param2, ISomething param3) where T : ISomething { object local1 = param1; ISomething local2 = param1; ... }

En este escenario, cualquiera de los parámetros proporcionados o locales podría representar valores encuadrados y podría no serlo con la misma facilidad. Es imposible decir por inspección casual, solo un examen de una combinación del tipo de tiempo de ejecución y la referencia por la cual se mantiene el valor puede determinarlo.


Si un tipo es un tipo de valor y su tipo estático es "dinámico" u "objeto", o una interfaz, siempre está encuadrado.

Si un tipo es un tipo de valor y su tipo estático es el tipo real, nunca se encuadra.


Similar a la respuesta de Allon , pero debería devolver la respuesta correcta para cualquier tipo sin generar un error en tiempo de compilación:

int i = 123; Console.WriteLine(IsBoxed(i)); // false object o = 123; Console.WriteLine(IsBoxed(o)); // true IComparable c = 123; Console.WriteLine(IsBoxed(c)); // true ValueType v = 123; Console.WriteLine(IsBoxed(v)); // true int? n1 = 123; Console.WriteLine(IsBoxed(n1)); // false int? n2 = null; Console.WriteLine(IsBoxed(n2)); // false string s1 = "foo"; Console.WriteLine(IsBoxed(s1)); // false string s2 = null; Console.WriteLine(IsBoxed(s2)); // false // ... public static bool IsBoxed<T>(T item) { return (item != null) && (default(T) == null) && item.GetType().IsValueType; } public static bool IsBoxed<T>(T? item) where T : struct { return false; }

(Aunque podría argumentar que el posible error en tiempo de compilación causado por el código de Allon es una característica, no un error: si usted golpea un error en tiempo de compilación, ¡entonces definitivamente no se trata de un tipo de valor sin caja!)