2012-06-26 15 views
5

ho questo tipo anonimo:Tipi anonimi a una matrice di oggetti?

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

Come posso fare un array di Objects (ogni elemento -> Cast di opporsi)

quindi a qualcosa di simile:

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

modifica

ps questa è solo una domanda di conoscenza sull'imparare a convertire da 1 tipo ad altro. so che posso inizializzare un array di oggetti dall'inizio. ma questa è una domanda di apprendimento.

scusa per non averlo menzionato.

ordine È importante ... perché? causa ConstructorInfo.Invoke è accettare

Tipo: System.Object [] Un array di valori che corrisponde al numero, cassa (!!!) e tipo (sotto i vincoli del legante default) dei parametri per questo ....

+3

I campi non hanno ordine implicito, quindi come funzionerà? – leppie

+0

Forse dovresti usare un tipo chiamato in questo caso. – Indy9000

+0

Non lo fai. C'è una differenza tra un 'Tipo' che ha membri e un array. È come dire: come faccio a prendere un 'System.Windows.Forms.Form' e convertire tutti i suoi membri in un' oggetto [] '. Questo non vuol dire che non sia fattibile, vuol dire che non è un'analogia corretta. – CodingGorilla

risposta

6

Dovresti usare la riflessione, in pratica. Non dovrebbe essere troppo difficile tramite Type.GetProperties, ma non so nulla di "built-in".

Come sottolineato da Leppie, l'ordinamento non è semplice: è necessario esaminare l'ordine dei parametri, che fornirebbe almeno l'ordine di tutti i tipi di proprietà. Se tu avessi solo tipi diversi, quello andrebbe bene.

Se non si preoccupano l'ordinamento, è possibile utilizzare:

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

EDIT: Ho solo pensato di qualcosa che effettivamente risolvere il problema, ma è specifica implementazione. Il compilatore C# genera tipi anonimi usando tipi generici. Così new { A = 5, B = "foo" } sarà effettivamente creare un tipo anonimo come questo:

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

modo da poter lavorare fuori i nomi di proprietà, al fine in base ai tipi generici di proprietà generici, quindi recuperare le proprietà in ordine dal tipo concreto. Ma è brutto ...

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

hi ive modificato. l'ordine è importante scusa se non l'ho menzionato. –

+0

@RoyiNamir: Mi sembra un brutto adattamento per i tipi anonimi, per essere onesti ... –

+0

lo so:) .... volevo solo vedere se potevo convertirlo da solo ... e no ... non ci sono riuscito. è solo una domanda provocatoria. (per l'apprendimento del corso) –

1

Vedi 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); 
} 

Si dovrebbe essere in grado di aggiungere al array usando GetValue invece di scrivere il nome della proprietà di consolarla.

+0

mantiene l'ordine? –

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

MODIFICA: Sembra che si desideri richiamare un costruttore di un tipo di un tipo anonimo.Sembra che l'unico modo in cui questo è possibile è se i nomi dei parametri corrispondono ai nomi di proprietà del tipo anonimo:

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

Se il vostro tipo anonimo avrà sempre le stesse proprietà che sono noti al momento della compilazione, poi si potrebbe utilizzare l'ovvio approccio esplicito:

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

La riflessione è la strada da percorrere se ne avete bisogno in modo dinamico creato. Se non ha bisogno di essere dinamici, è possibile ovviamente fare in questo modo, ma presumo che hai già pensato a questo:

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

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

Potrebbe fornire una prospettiva più approfondita sul problema, come sei non ci sta dando molto da fare, forse c'è una soluzione migliore se non inizi con un tipo anon?

0

penso che questo è meglio di soluzione Jon Skeet, dato che si basa sul risultato di ToString piuttosto che su più sottili dettagli di come i tipi anonimi vengono generati:

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(); 

Si potrebbe anche essere in grado di leggere la stringa costanti dal codice metodo ToString (myAnon.GetType().GetMethod("ToString").GetMethodBody()) se è necessario proteggere contro la possibilità che un oggetto nel tipo anonimo venga sottoposto a rendering con " = " al suo interno, eliminando in tal modo il parser semplicistico.