2012-01-01 45 views
7

Tôi đang tạo một hệ thống biến một tập lệnh nhỏ thành một dll. Tôi gặp phải một vấn đề khi tôi cố gắng để có một lớp giá trị nullable và làm cho nó giá trị mặc định của một tham số. Vấn đề là tôi cần phải tạo một thể hiện của người dùng được chọn nullable trong trình biên dịch và thiết lập nó như là hằng số.Tạo một đối tượng nullable qua Activator.CreateInstance trả về null

Thật không may, bất cứ khi nào tôi sử dụng Activator.CreateInstance(NullableType) (trong đó NullableType là loại được tạo từ đầu vào của người dùng), tôi nhận được null làm giá trị trả lại. Ví dụ: chỉ cần thực hiện:

object Test = Activator.CreateInstance(typeof(Nullable<int>)); 
Console.WriteLine(Test == null); 

trả về true. Điều này CHỈ xảy ra với Nullables. Một cấu trúc được tạo ra trong C#, thậm chí một cấu trúc chung, được tạo ra tốt. Heck, nếu tôi sao chép & dán nullable từ DotNetReflector (và loại bỏ TypeDependencyAttribute, TargetPatchingOptOutAttribute, và ThrowHelper cuộc gọi kể từ khi tôi không có quyền truy cập vào những người), nó cho thấy sai ở trên.

Điều gì đang xảy ra? Có cách nào khác có thể để tạo ra một nullable khi tôi không biết các thông số chung cho đến khi thời gian chạy?

Trả lời

1

Sự cố xảy ra ở ParameterBuilder.SetConstant, không phải Activator.CreateInstance. SetConstant là một hàm để xác định giá trị mặc định của tham số tùy chọn và yêu cầu giá trị cụ thể được cung cấp dưới dạng hằng số. Đối với các lớp ref, null là giá trị cụ thể hợp lệ, nhưng đối với các lớp giá trị trước khi tạo Nullable<>, null không phải là giá trị hợp lệ. Làm thế nào để bạn unbox null thành một ví dụ int? Vì vậy, SetConstant các loại giá trị được kiểm tra để xem giá trị cụ thể được truyền vào dưới dạng hằng số là null và ném ArgumentException dưới dạng lỗi mô tả hơn số NullReferenceException bạn muốn nhận unboxing một null vào một lớp giá trị.

Trong trường hợp Nullable<>, null hiện là giá trị cụ thể hợp lệ cho một lớp giá trị. Nullable<> chính nó là một lớp giá trị, như được thấy với Activator.CreateInstance và unboxing null thành một Nullable<int> có ý nghĩa. Đây là nơi SetConstant có lỗi: không thể tính đến điều này và ném lỗi 'mô tả' cho những gì không thực sự là lỗi. Thay cho một bugfix từ Microsoft, bất kỳ cuộc gọi nào đến SetConstant với một null Nullable<> sẽ phải thực hiện hành vi được bảo vệ bởi điều kiện không chính xác. Điều này có nghĩa là đào sâu vào các phương thức và trường riêng tư của ParameterBuilder bằng cách sử dụng sự phản chiếu. Dưới đây là mã tôi đã thực hiện để xử lý chỉ trường hợp này. Chức năng tiêu chuẩn SetConstant nên được sử dụng trong các tình huống không hiển thị lỗi.

//ModuleBuilder module : a parameter passed into the containing function, the module which is being built (which contains the method that has the optional parameter we are setting the constant for) 
//ParameterBuilder optParam : A parameter passed into the containing function, the parameter that is being built which is to have the null default value. 
MethodInfo method = typeof(TypeBuilder).GetMethods(BindingFlags.Static | BindingFlags.NonPublic) 
    .Where(m => m.Name == "SetConstantValue" && m.GetParameters().Length > 0 && m.GetParameters()[0].ParameterType.Name == "RuntimeModule") 
    .Single(); 
var RuntimeHandle = typeof(ModuleBuilder).GetMethod("GetNativeHandle", BindingFlags.NonPublic | BindingFlags.Instance); 
method.Invoke(null, new object[] 
{ 
    RuntimeHandle.Invoke(module, new object[]{}), 
    optParam.GetToken().Token, 
    0x12, 
    null 
}); 

Tôi đã báo cáo lỗi cho Microsoft.Họ trả lời rằng nó sẽ không được sửa trong .NET 3.5, nhưng nó đã được thêm vào cơ sở dữ liệu lỗi nội bộ.

UPDATE:

Các lỗi đã được cố định trong .NET 4.0. ParameterBuilder.SetConstant hiện có chi nhánh constant == null có điều kiện để kiểm tra xem loại giá trị có phải là loại chung có nguồn gốc từ Nullable<> và chỉ ném ngoại lệ nếu không.

+0

Mô-đun và tham chiếu optParam là gì? –

+0

1. Hack rất điên. 2. Nullables là null trong một hình thức đối tượng - điều này là do thiết kế. 3. Thêm mô tả xin vui lòng. – Vlad

+0

Vâng, đó là một hack điên. Đó là để làm việc xung quanh 'ParameterBuilder.SetConstant' có một' if (value == null) ném mới ArgumentException (...) '. Mã nguồn gốc thực tế mà 'ParameterBuilder.SetConstant' sử dụng (đó là riêng tư và những gì tôi đang phản ánh ở trên) là tốt với Nullables là null, bởi vì nó là do thiết kế. Nó chỉ đơn giản là chức năng quản lý công cộng, được quản lý có chứa một lỗi và yêu cầu bỏ qua. Lỗi này đã được sửa chữa, vì vậy câu trả lời này không còn cần thiết trừ khi bạn đang nhắm mục tiêu 3.5 trở xuống. –

6

Từ this MSDN blog:

Activator.CreateInstance không bao giờ có thể được dự kiến ​​sẽ trả về null trước; với DCR này, nó sẽ trả về null khi tạo thể hiện của loại Nullable nhưng không cung cấp giá trị T không null. Ví dụ: Activator.CreateInstance (typeof (Int32?)) Trả về giá trị rỗng.

Sự cố phải làm với cách biến số Nullable<T> được đóng hộp như được giải thích bởi bài đăng trên blog.

+0

Điều đó trả lời một trong hai câu hỏi của tôi. Ngoài ra, tôi tìm thấy câu trả lời này một vài phút trước khi nhìn thấy bạn qua bài viết MSDN: http://msdn.microsoft.com/en-us/library/ms228597.aspx. Rằng lá: Làm thế nào để tôi tạo ra một nullable mà không biết các thông số của nó cho đến khi thời gian chạy, và vượt qua nó để ParameterBuilder.SetConstant? Ngay cả khi vượt qua một null nullable để SetContstant thất bại vì những lý do được trích dẫn trong blog và bài viết MSDN. –

+0

Tôi tình cờ gặp một câu hỏi tương tự trong nghiên cứu của mình. Tình hình của họ hơi khác một chút mặc dù: http://stackoverflow.com/questions/1488706/set-property-nullable-by-reflection –

+0

Tôi không biết liệu nó có trả lời câu hỏi thứ hai của bạn hay không, nhưng bạn có thể tự động tạo kiểu chung của mình tại thời gian chạy dựa trên các yêu cầu của bạn bằng cách sử dụng Reflection (http://stackoverflow.com/questions/2078914/c-sharp-dynamic-generic-type) và chuyển loại kết quả động tới 'Activator.CreateInstance' khi bạn hiển thị trong câu hỏi của mình. Tôi thực sự có kinh nghiệm với điều đó mặc dù vậy nếu bạn cần giúp đỡ xin vui lòng cho chúng tôi biết. –

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