2012-06-26 83 views
5

我有这样的匿名类型:对象数组的匿名类型?

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

我怎样才能使它的Objects数组(每个元素 - >投反对)

因此喜欢的东西:

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

编辑

ps这只是一个关于学习从1类型转换为其他类型的知识问题。 我知道我可以从一开始就初始化一个对象数组。但这是一个学习问题。

抱歉没有提到它。

顺序重要......为什么?原因ConstructorInfo.Invoke正在接受

类型:System.Object []值的数组,为了这个匹配 参数的数量, 顺序(!!!)和类型(默认粘结剂的约束下) ...

+3

字段没有隐含的顺序,所以这将如何工作? – leppie

+0

也许你应该在这种情况下使用命名类型。 – Indy9000

+0

你不知道。 “成员类型”和数组之间有区别。这就像在说:我如何获取'System.Windows.Forms.Form'并将其所有成员转换为'object []'。这并不是说它不可行,而是说它不是一个合适的比喻。 – CodingGorilla

回答

6

你基本上必须使用反射。通过Type.GetProperties不应该太难,但我不知道任何“内置”。

正如leppie指出的那样,订购并不简单 - 您必须检查参数的顺序,这些参数至少会为您提供所有类型属性的顺序。如果你只有不同的类型,那就没问题了。

如果你不关心的排序,你可以使用:

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

编辑:我只是想的东西,这将真正修复它,但它是实现特定的。 C#编译器使用泛型类型生成匿名类型。所以new { A = 5, B = "foo" }实际上将创建一个匿名类型是这样的:

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

,因此您可以基于通用类型的一般属性,才能制定出属性的名称,然后从具体类型,以便获取属性。但它的丑陋......

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

已编辑。顺序很重要。对不起,没有提到它。 –

+0

@RoyiNamir:这对于匿名类型来说感觉不太合适,说实话... –

+0

我知道:)....只是想看看我是否可以自己将其转换...并且不...没有成功。它只是一个逗笑的问题。 (用于学习课程) –

1

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

你应该能够使用GetValue,而不是写属性名称控制台添加到阵列。

+0

它保持秩序? –

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

编辑:它看起来像你想从匿名类型调用某种类型的构造函数。看起来,这是唯一可行的办法是,如果该参数名称相匹配的匿名类型的属性名称:

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

如果您的匿名类型将永远有其是在编译时已知相同的属性,那么你可以使用明显的方法:

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

反射是要走的路,如果你需要动态创建。如果它并不需要是动态的,你可以很明显不喜欢这样,但我假设你已经想到了这一点:

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

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

你能对你的问题提供了一个更深入的视角,你没有给我们太多的帮助,如果你不是从anon类型开始,也许有更好的解决方案?

0

我觉得这是比乔恩斯基特的更好的解决方案,因为它依赖于ToString结果上,而不是如何匿名类型产生微妙的细节:

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

您可能还能够读取字符串常量从myAnonToString方法代码(myAnon.GetType().GetMethod("ToString").GetMethodBody()),如果您需要防止匿名类型中的对象在其中呈现" = "的可能性,从而抛弃简单的分析器。