2009-06-17 31 views
11

Tôi hiện đang viết một số mã để lưu các đối tượng chung vào XML bằng cách sử dụng sự phản chiếu trong C#.C# sử dụng sự phản chiếu để tạo ra một cấu trúc

Vấn đề là khi đọc XML trở lại trong một số đối tượng là cấu trúc và tôi không thể tìm ra cách khởi tạo cấu trúc. Đối với một lớp học, tôi có thể sử dụng

ConstructorInfo constructor = SomeClass.GetConstructor(Type.EmptyTypes); 

tuy nhiên, đối với một cấu trúc, không có hàm tạo nào không có tham số sao cho mã trên đặt hàm tạo thành null. Tôi cũng đã thử

SomeStruct.TypeInitializer.Invoke(null) 

nhưng điều này sẽ tạo ra quan hệ thành viên. Google không có lượt truy cập đầy hứa hẹn. Bất kỳ trợ giúp sẽ được đánh giá cao.

Trả lời

14

Nếu giá trị là cấu trúc, chúng có thể là là không thay đổi - vì vậy bạn không muốn gọi hàm tạo tham số, nhưng giá trị thích hợp làm đối số hàm tạo.

Nếu các cấu trúc không bất biến, sau đó chạy trốn khỏi chúng càng nhanh càng tốt, nếu bạn có thể ... nhưng nếu bạn hoàn toàn có để làm điều này, sau đó sử dụng Activator.CreateInstance(SomeClass). Bạn sẽ phải rất cẩn thận khi bạn sử dụng sự phản chiếu để thiết lập các thuộc tính hoặc các trường trên kiểu giá trị mặc dù không có sự quan tâm đó, bạn sẽ tạo một bản sao, thay đổi giá trị trên bản sao đó, và sau đó vứt nó đi. Tôi nghi ngờ rằng nếu bạn làm việc với một phiên bản đóng hộp trong suốt, bạn sẽ ổn thôi:

using System; 

// Mutable structs - just say no... 
public struct Foo 
{ 
    public string Text { get; set; } 
} 

public class Test 
{ 
    static void Main() 
    { 
     Type type = typeof(Foo); 

     object value = Activator.CreateInstance(type); 
     var property = type.GetProperty("Text"); 
     property.SetValue(value, "hello", null); 

     Foo foo = (Foo) value; 
     Console.WriteLine(foo.Text); 
    } 
} 
+0

Đăng trong chủ đề sử thi ... Ngoài ra, upvote cho câu trả lời ngắn gọn, gọn gàng. –

+0

Vấn đề là ngay bây giờ, Activator.CreateInstance trả về một RuntimeType thay vì loại tôi đã yêu cầu: (Điều đó có nghĩa là GetFields không trả về giá trị nào. –

+0

@Marcel: Có vẻ như bạn nên đặt một câu hỏi mới với [mcve] –

1

Chỉ cần thêm - với bất biến cấu trúc, bạn có khả năng phải làm phù hợp tham số để các nhà xây dựng. Thật không may điều này là khó khăn khi có thể có nhiều cấu trúc, và đặc biệt là vì một số loại có phương thức "Tạo" riêng biệt thay vì một hàm tạo công khai. Nhưng giả bạn đã thực hiện phù hợp, bạn vẫn có thể sử dụng Activator.CreateInstance:

Type type = typeof(Padding); // just an example 
    object[] args = new object[] {1,2,3,4}; 
    object obj = Activator.CreateInstance(type, args); 

Tuy nhiên - mã để chọn một nhà xây dựng (ở trên có 3 ...) là không dễ dàng. Bạn có thể nói "chọn phức tạp nhất" và sau đó cố gắng để phù hợp với tên tham số tên thuộc tính (case insensitive) ...

Một ví dụ ngây thơ:

static void Main() { 
    Dictionary<string, object> propertyBag = 
     new Dictionary<string, object>(); 
    // these are the values from your xml 
    propertyBag["Left"] = 1; 
    propertyBag["Top"] = 2; 
    propertyBag["Right"] = 3; 
    propertyBag["Bottom"] = 4; 
    // the type to create 
    Type type = typeof(Padding); 

    object obj = CreateObject(type, propertyBag); 

} 
static object CreateObject(Type type, IDictionary<string,object> propertyBag) 
{ 
    ConstructorInfo[] ctors = type.GetConstructors(); 
    // clone the property bag and make it case insensitive 
    propertyBag = new Dictionary<string, object>(
     propertyBag, StringComparer.OrdinalIgnoreCase); 
    ConstructorInfo bestCtor = null; 
    ParameterInfo[] bestParams = null; 
    for (int i = 0; i < ctors.Length; i++) 
    { 
     ParameterInfo[] ctorParams = ctors[i].GetParameters(); 
     if (bestCtor == null || ctorParams.Length > bestParams.Length) 
     { 
      bestCtor = ctors[i]; 
      bestParams = ctorParams; 
     } 
    } 
    if (bestCtor == null) throw new InvalidOperationException(
     "Cannot create - no constructor"); 
    object[] args = new object[bestParams.Length]; 
    for (int i = 0; i < bestParams.Length; i++) 
    { 
     args[i] = propertyBag[bestParams[i].Name]; 
     propertyBag.Remove(bestParams[i].Name); 
    } 
    object obj = bestCtor.Invoke(args); 
    // TODO: if we wanted, we could apply any unused keys in propertyBag 
    // at this point via properties 
    return obj; 
} 
2

CreateInstance sẽ không giúp bạn với cấu trúc không có các nhà thầu được định nghĩa rõ ràng.

FormatterServices.GetUninitializedObject(Type type); 

Điều này thực hiện thủ thuật với cấu trúc trống.

Các vấn đề liên quan