2012-06-26 14 views
5

tengo este tipo anónimo:¿Tipos anónimos a una matriz de objetos?

var t= new {a=1,b="lalala",c=DateTime.Now}; 

¿Cómo puedo hacer que un conjunto de Objects (cada elemento -> Reparto de oponerse)

por lo tanto, a algo como:

object[] v = new object[] {1,"lalala",DateTime.Now}; 

edición

ps esta es solo una pregunta de conocimiento sobre aprender a convertir de 1 tipo a otro. sé que puedo inicializar una matriz de objetos desde el principio. pero esta es una pregunta de aprendizaje.

lo siento por no mencionarlo.

orden Es importante ... ¿por qué? causa ConstructorInfo.Invoke está aceptando

Tipo: System.Object [] Una matriz de valores que coincida con el número, orden (!!!) y tipo (bajo las restricciones del aglutinante por defecto) de los parámetros para este ....

+3

Los campos no tienen un orden implícito, ¿cómo funcionará? – leppie

+0

Quizás deba usar un tipo con nombre en este caso. – Indy9000

+0

No es así. Hay una diferencia entre un 'Tipo' que tiene miembros y una matriz. Es como decir: ¿Cómo tomo un 'System.Windows.Forms.Form' y convierto todos sus miembros en un' object [] '. Eso no quiere decir que no sea factible, es decir que no es una analogía apropiada. – CodingGorilla

Respuesta

6

Tendría que usar la reflexión, básicamente. No debería ser demasiado difícil a través de Type.GetProperties, pero no sé de nada "incorporado".

Como señaló Leppie, el que ordena no es simple - tendría que examinar el orden de los parámetros, que al menos le daría el orden de todos los tipos de las propiedades. Si solo tienes diferentes tipos, estaría bien.

Si no se preocupan por el ordenamiento, puede utilizar:

var array = t.GetType() 
      .GetProperties() 
      .Select(p => p.GetValue(t, null)) 
      .ToArray(); 

EDIT: Acabo de ocurrir algo que en realidad lo arreglará, pero es específico de la implementación. El compilador de C# genera tipos anónimos usando tipos genéricos. Así new { A = 5, B = "foo" } genera realmente un tipo anónimo de esta manera:

class <>_Anon<TA, TB> 
{ 
    internal <>_Anon(TA a, TB b) 
} 

para que pueda resolver los nombres de propiedad en orden basado en los tipos genéricos de las propiedades genéricas, a continuación, ir a buscar las propiedades con el fin del tipo inmediato. Pero es fea ...

using System; 
using System.Linq; 
using System.Reflection; 

class Test  
{ 
    // Note: this uses implementation details of anonymous 
    // types, and is basically horrible. 
    static object[] ConvertAnonymousType(object value) 
    { 
     // TODO: Validation that it's really an anonymous type 
     Type type = value.GetType(); 
     var genericType = type.GetGenericTypeDefinition(); 
     var parameterTypes = genericType.GetConstructors()[0] 
             .GetParameters() 
             .Select(p => p.ParameterType) 
             .ToList(); 
     var propertyNames = genericType.GetProperties() 
             .OrderBy(p => parameterTypes.IndexOf(p.PropertyType)) 
             .Select(p => p.Name); 

     return propertyNames.Select(name => type.GetProperty(name) 
               .GetValue(value, null)) 
          .ToArray(); 

    } 

    static void Main() 
    { 
     var value = new { A = "a", Z = 10, C = "c" }; 
     var array = ConvertAnonymousType(value); 
     foreach (var item in array) 
     { 
      Console.WriteLine(item); // "a", 10, "c" 
     } 
    } 
} 
+0

hola editado. el orden es importante lo siento por no mencionarlo. –

+0

@RoyiNamir: Esto se siente como un mal ajuste para los tipos anónimos, para ser honesto ... –

+0

lo sé:) .... solo quería ver si podía convertirlo yo mismo ... y no ... no tuvo éxito. .es solo una pregunta burlona. (para aprender por supuesto) –

1

Ver http://blogs.msdn.com/b/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx:

static void Main() 
{ 
    //Anonymous Type 
    var anyType = new 
    { 
     IntID = 1, 
     StringName = "Wriju" 
    }; 

    Type t = anyType.GetType(); 
    PropertyInfo[] pi = t.GetProperties(); 
    foreach (PropertyInfo p in pi) 
    { 
     //Get the name of the prperty 
     Console.WriteLine(p.Name); 
    } 

    //Using LINQ get all the details of Property 
    var query = from p in t.GetProperties() 
       select p; 
    ObjectDumper.Write(query); 
} 

Usted debe ser capaz de añadir a la matriz mediante GetValue en lugar de escribir el nombre de propiedad a la consola.

+0

¿mantiene el orden? –

4
public object[] ToPropertyArray(object o) 
{ 
    return o.GetType.GetProperties() 
     .Select(p => p.GetValue(o, null)) 
     .ToArray(); 
} 

EDITAR: Parece que desea invocar un constructor de algún tipo de un tipo anónimo.Parece que la única manera de que esto es posible es que si los nombres de los parámetros coinciden con los nombres de las propiedades del tipo anónimo:

public static T ConstructFromAnonymous<T>(object anon) 
{ 
    //get constructors for type ordered by number of parameters 
    var constructors = typeof(T).GetConstructors().OrderByDescending(c => c.GetParameters().Length); 

    //get properties from anonymous object 
    Dictionary<string, PropertyInfo> properties = anon.GetType() 
     .GetProperties() 
     .ToDictionary(p => p.Name); 

    ConstructorInfo bestMatch = constructors.FirstOrDefault(ci => IsMatch(ci, properties)); 
    if (bestMatch != null) 
    { 
     var parameters = bestMatch.GetParameters(); 
     object[] args = parameters.Select(p => properties[p.Name].GetValue(anon, null)).ToArray(); 
     return (T)bestMatch.Invoke(args); 
    } 
    else throw new ArgumentException("Cannot construct type"); 
} 

private static bool IsMatch(ConstructorInfo ci, Dictionary<string, PropertyInfo> properties) 
{ 
    var parameters = ci.GetParameters(); 
    return parameters.All(p => properties.ContainsKey(p.Name) && p.ParameterType.IsAssignableFrom(properties[p.Name].PropertyType)); 
} 
0

Si su tipo anónimo siempre tendrá las mismas propiedades que se conocen en tiempo de compilación, entonces podría utilizar el enfoque explícito obvio:

var t = new { a = 1, b = "lalala", c = DateTime.Now }; 
object[] v = new object[] { t.a, t.b, t.c }; 
0

La reflexión es el camino a seguir si la necesita creada dinámicamente. Si no tiene que ser dinámico Naturalmente, también puede hacerlo de esta manera, pero supongo que ya ha pensado en esto:

var t = new { a = 1, b = "lalala", c = DateTime.Now }; 

object[] v = new object[] { t.a, t.b, t.c }; 

Podría dar una perspectiva más a fondo sobre su problema ya que estás no nos da mucho para seguir, tal vez haya una mejor solución si no comienzas con un tipo anon?

0

creo que esto es mejor que la solución de Jon Skeet, ya que se basa en el resultado de ToString en lugar de en los detalles más sutiles de cómo los tipos anónimos son generados:

var myAnon = new { a = "hi", b185310 = "lo" }; 
var names = Regex.Matches(myAnon.ToString(), @"([a-zA-Z0-9]+) = "); 
var objArray = names.Cast<Match>().Select(name => myAnon.GetType().GetProperty(name.Groups[1].ToString()).GetValue(myAnon, null)).ToArray(); 

También podría ser capaz de leer la cadena constantes del código de método myAnonToString (myAnon.GetType().GetMethod("ToString").GetMethodBody()) si necesita protegerse contra la posibilidad de que un objeto en el tipo anónimo se represente con " = ", arrojando así el analizador simplista.

Cuestiones relacionadas