dynamically - dynamic properties c#
¿Por qué no puedo hacer esto? Dinámico x=nuevo ExpandoObject{Foo=12, Bar="doce"} (6)
¿Estoy haciendo algo mal o el siguiente código no es posible?
Realmente no es posible. Lo que está a la izquierda del operador de asignación debe ser una propiedad o campo conocido en tiempo de compilación, y obviamente ese no es el caso para los objetos de expansión.
¿Por qué el equipo C # optaría por no permitir la misma sintaxis de inicialización que los objetos normales, los objetos anónimos y los enumerables / listas?
La forma en que formula la pregunta indica el error lógico. Las características no se implementan de manera predeterminada y luego corremos rechazando casi todas porque creemos que son una mala idea. Las características no se implementan de manera predeterminada y deben implementarse para que funcionen.
El primer paso para implementar cualquier característica es que alguien tenga que pensar en ello en primer lugar. Que yo sepa, nunca lo hicimos. En particular, hubiera sido bastante difícil para la persona que diseña los inicializadores de objetos en 2006 saber que en 2010 íbamos a agregar "dinámico" al lenguaje, y diseñar la función en consecuencia. Las características siempre están diseñadas por diseñadores que se mueven hacia adelante en el tiempo, no hacia atrás en el tiempo. Solo recordamos el pasado, no el futuro.
De todos modos, es una buena idea, así que gracias por compartirlo. Ahora que alguien lo ha pensado, podemos trabajar en los próximos pasos, como decidir si es la mejor idea sobre la cual podemos gastar nuestro presupuesto limitado, diseñarlo, escribir la especificación, implementarlo, probarlo, documentarlo y enviándolo a los clientes.
No esperaría que nada de eso sucediera pronto; estamos un poco ocupados con todo este negocio asincrónico y WinRT que anunciamos en Build la semana pasada.
¿Estoy haciendo algo mal o el siguiente código no es posible?
dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" };
Si esto realmente no es posible, ¿hay otra forma de una línea para instanciar un ExpandoObject con dos propiedades?
¿Por qué el equipo C # optaría por no permitir la misma sintaxis de inicialización que los objetos normales, los objetos anónimos y los enumerables / listas?
Actualizar
Hice esta pregunta porque estaba intentando mostrarle a un entusiasta de Pearl las nuevas características dinámicas de C #, pero luego me quedé estancado al no poder hacer lo que pensé que era una instanciación lógica de un ExpandoObject
. Gracias a la respuesta de Hans Passant, me doy cuenta de que ExpandoObject
era la herramienta incorrecta para el trabajo. Mi verdadero objetivo era usar las características dinámicas de C # para devolver dos valores nombrados de un método. Como señala Hans, la palabra clave dynamic
es perfecta para esto. No necesitaba un ExpandoObject
, con todos sus gastos generales, para hacer esto.
Por lo tanto, si desea devolver un par de valores con nombre de un método y no está preocupado por la seguridad del tipo, Intellisense, refactorización o rendimiento, esto funciona bastante bien:
public dynamic CreateFooBar()
{
return new { Foo = 42, Bar = "Hello" };
}
Uso:
dynamic fooBar = CreateFooBar();
var foo = fooBar.Foo;
var bar = fooBar.Bar;
Dynamitey (PCL de código abierto y encontrado en nuget) tiene una sintaxis para inicializar expandos que pueden estar en línea.
//using Dynamitey.DynamicObjects
var x = Build<ExpandoObject>.NewObject(Foo:12, Bar:"twelve");
Ese tipo de sintaxis de inicializador es posible porque ya hay una propiedad con un get y un setter. Con el objeto de expansión aún no existen esas propiedades de lo que puedo decir.
Hay una mejor trampa para ratones que ExpandoObject. La palabra clave dinámica maneja tipos anónimos con aplomb:
class Program {
static void Main(string[] args) {
dynamic x = new { Foo = 12, Bar = "twelve" };
Display(x);
}
static void Display(dynamic x) {
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
}
Un desafortunado problema es que el compilador de C # genera el tipo anónimo que brinda a los miembros solo acceso interno . Lo que significa que obtendrá un error de tiempo de ejecución cuando intente acceder a los miembros en otro ensamblado. Gorrón.
Considere una tupla , muy mejorada en C # v7.
Una forma mucho más simple de hacer esto:
Func<Dictionary<string, object>, ExpandoObject> parse = dict =>
{
var expando = new ExpandoObject();
foreach (KeyValuePair<string, object> entry in dict)
{
expando.Add(entry.Key, entry.Value);
}
return expando;
};
Luego solo llame a la función de análisis y pase el diccionario como parámetro. Esto, por supuesto, se puede implementar en un método en lugar de una función.
Una solución que funcionó para mí es el método de extensión ToExpando()
de Yan Cui ( source ):
public static class DictionaryExtensionMethods
{
/// <summary>
/// Extension method that turns a dictionary of string and object to an ExpandoObject
/// </summary>
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
{
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>) expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>) kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection) kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>) item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}
return expando;
}
}
Ejemplo de uso:
public const string XEntry = "ifXEntry";
public static readonly dynamic XEntryItems = new Dictionary<string, object>
{
{ "Name", XEntry + ".1" },
{ "InMulticastPkts", XEntry + ".2" },
{ "InBroadcastPkts", XEntry + ".3" },
{ "OutMulticastPkts", XEntry + ".4" },
{ "OutBroadcastPkts", XEntry + ".5" },
{ "HCInOctets", XEntry + ".6" },
{ "HCInUcastPkts", XEntry + ".7" },
{ "HCInMulticastPkts", XEntry + ".8" },
{ "HCInBroadcastPkts", XEntry + ".9" },
{ "HCOutOctets", XEntry + ".10" },
{ "HCOutUcastPkts", XEntry + ".11" },
{ "HCOutMulticastPkts", XEntry + ".12" },
{ "HCOutBroadcastPkts", XEntry + ".13" },
{ "LinkUpDownTrapEnable", XEntry + ".14" },
{ "HighSpeed", XEntry + ".15" },
{ "PromiscuousMode", XEntry + ".16" },
{ "ConnectorPresent", XEntry + ".17" },
{ "Alias", XEntry + ".18" },
{ "CounterDiscontinuityTime", XEntry + ".19" },
}.ToExpando();
Luego puede usar propiedades como XEntryItems.Name
.
PD: vote UserVoice para dar soporte a los inicializadores de objetos en ExpandoObjects.