2012-06-26 18 views
5

Tôi có loại vô danh này:Các loại ẩn danh cho một mảng đối tượng?

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

Làm thế nào tôi có thể làm cho nó một mảng của Objects (mỗi phần tử -> Dàn diễn viên phản đối)

do đó một cái gì đó như:

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

chỉnh sửa

ps đây chỉ là một câu hỏi kiến ​​thức về việc học cách chuyển đổi từ loại này sang loại khác. tôi biết tôi có thể khởi tạo một mảng đối tượng ngay từ đầu. nhưng đây là một câu hỏi học tập.

xin lỗi vì đã không đề cập đến nó.

yêu cầu Quan trọng ... tại sao? nguyên nhân ConstructorInfo.Invoke được chấp nhận

Loại: System.Object [] Một mảng các giá trị phù hợp với số lượng, trật tự (!!!) và loại (dưới sự ràng buộc của các chất kết dính mặc định) của các thông số cho điều này ....

+3

Các trường không có thứ tự ngầm, vì vậy cách thức hoạt động của nó? – leppie

+0

Có lẽ bạn nên sử dụng một loại có tên trong trường hợp này. – Indy9000

+0

Bạn không. Có sự khác biệt giữa một 'Loại' có các thành viên và một mảng. Điều đó giống như nói: Làm thế nào để lấy một 'System.Windows.Forms.Form' và chuyển đổi tất cả thành viên của nó thành một' object [] '. Đó không phải là để nói rằng nó không thể làm được, đó là để nói nó không phải là một tương tự thích hợp. – CodingGorilla

Trả lời

6

Bạn sẽ phải sử dụng phản chiếu, về cơ bản. Nó không quá khó qua Type.GetProperties, nhưng tôi không biết gì về "tích hợp".

Như leppie chỉ ra, đặt hàng không đơn giản - bạn phải kiểm tra thứ tự các tham số, ít nhất sẽ cung cấp cho bạn thứ tự của tất cả các loại thuộc tính. Nếu bạn chỉ có các loại khác nhau, điều đó sẽ ổn thôi.

Nếu bạn không quan tâm đến thứ tự, bạn có thể sử dụng:

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

EDIT: Tôi vừa mới nghĩ đến một cái gì đó thực sự sẽ sửa chữa nó, nhưng đó là thực hiện cụ thể. Trình biên dịch C# tạo ra các kiểu ẩn danh bằng cách sử dụng các kiểu generic. Vì vậy new { A = 5, B = "foo" } sẽ thực sự tạo ra một loại vô danh như thế này:

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

để bạn có thể làm việc ra các tên thuộc tính theo thứ tự dựa trên các loại chung của các thuộc tính chung chung, sau đó lấy các thuộc tính theo thứ tự từ loại bê tông. Nhưng đó là xấu xí ...

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 đã chỉnh sửa. thứ tự là quan trọng. xin lỗi vì đã không đề cập đến nó. –

+0

@RoyiNamir: Điều này cảm thấy như một sự phù hợp xấu cho các loại vô danh, phải trung thực ... –

+0

tôi biết:) .... chỉ muốn xem nếu tôi có thể chuyển đổi nó bản thân mình ... và nope ... didnt thành công. nó chỉ là một câu hỏi trêu chọc. (cho việc học tập) –

1

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

Bạn sẽ có thể thêm vào mảng sử dụng GetValue thay vì viết tên thuộc tính để an ủi.

+0

nó có giữ nguyên thứ tự không? –

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

EDIT: Có vẻ như bạn muốn gọi một hàm tạo của một loại nào đó từ một loại ẩn danh.Có vẻ như cách duy nhất này có thể là nếu tên tham số phù hợp với tên thuộc tính của các loại vô danh:

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

Nếu loại vô danh của bạn sẽ luôn có tính chất tương tự được biết đến tại thời gian biên dịch, sau đó bạn có thể sử dụng cách tiếp cận rõ ràng rõ ràng:

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

Phản ánh là cách cần thực hiện nếu bạn cần tạo động. Nếu nó không cần phải năng động, bạn rõ ràng có thể làm điều đó như thế này nhưng tôi cho rằng bạn đã nghĩ về điều này:

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

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

Bạn có thể cung cấp cái nhìn sâu sắc hơn về vấn đề của mình khi bạn không cho chúng ta nhiều để tiếp tục, có lẽ có một giải pháp tốt hơn nếu bạn không bắt đầu với một loại anon?

0

Tôi nghĩ rằng đây là tốt hơn so với giải pháp của Jon Skeet, vì nó phụ thuộc vào kết quả của ToString chứ không phải trên các chi tiết tinh vi hơn về cách các kiểu nặc danh được tạo ra:

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

Bạn cũng có thể có khả năng đọc chuỗi hằng số từ myAnon 's ToString mã phương thức (myAnon.GetType().GetMethod("ToString").GetMethodBody()) nếu bạn cần bảo vệ chống lại khả năng của một đối tượng trong loại ẩn danh đang được hiển thị với " = " trong đó, do đó sẽ loại bỏ trình phân tích cú pháp đơn giản.