2011-01-13 27 views
78

Tôi muốn kiểm tra xem một kiểu được biết đến trong thời gian chạy có cung cấp một hàm tạo tham số không. Lớp Type không mang lại bất kỳ điều gì hứa hẹn, vì vậy tôi giả sử tôi phải sử dụng sự phản chiếu?Làm cách nào để kiểm tra xem một loại có cung cấp một hàm tạo tham số không?

+0

Tôi nghĩ rằng đó là đúng – kenny

+2

Sidenote: Có một ràng buộc chung cho các nhà xây dựng parameterless. – CodesInChaos

+1

là câu hỏi liệu loại ** chỉ ** có cung cấp một hàm tạo tham số hoặc nếu nó cung cấp một cái không? – BrokenGlass

Trả lời

132

Các Type lớp phản ánh. Bạn có thể làm:

Type theType = myobject.GetType(); // if you have an instance 
// or 
Type theType = typeof(MyObject); // if you know the type 

var constructor = theType.GetConstructor(Type.EmptyTypes); 

Nó sẽ trả về null nếu không có hàm tạo tham số.


Nếu bạn cũng muốn tìm nhà xây dựng tư nhân, sử dụng hơi dài:

var constructor = theType.GetConstructor(
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
    null, Type.EmptyTypes, null); 

Có một caveat với nhiều loại giá trị, mà aren't allowed to have a default constructor. Bạn có thể kiểm tra xem bạn có loại giá trị hay không bằng cách sử dụng thuộc tính Type.IsValueType và tạo các phiên bản bằng cách sử dụng Activator.CreateInstance(Type);

+2

điều này sẽ không tìm thấy ctors riêng fyi –

+2

Điều này cũng sẽ không hoạt động đối với các loại giá trị. – leppie

+2

Nhận xét đã được giải quyết ở trên. –

12

Có, bạn phải sử dụng Phản chiếu. Nhưng bạn đã làm điều đó khi bạn sử dụng GetType()

Cái gì như:

var t = x.GetType(); 
var c = t.GetConstructor(new Type[0]); 
if (c != null) ... 
6

này nên làm việc:

myClass.GetType().GetConstructors() 
        .All(c=>c.GetParameters().Length == 0) 
+1

Không phải ý của tôi, nhưng xin đừng xóa - đó là một vấn đề liên quan và một thông tin tốt đẹp. – mafu

1

Có, bạn phải sử dụng sự phản chiếu.

object myObject = new MyType(); 
Type type = myObject.GetType(); 
ConstructorInfo conInfo = type.GetConstructor(new Type[0]); 
3

Tùy thuộc vào tình hình của bạn, bạn cũng có thể sử dụng một hạn chế loại generic:

public void DoSomethingWith<T>(T myObject) where T:new() {...} 

Tờ khai phương pháp trên sẽ hạn chế các loại tham số cho bất kỳ đối tượng có thể được khởi tạo với một constructor parameterless. Ưu điểm ở đây là trình biên dịch sẽ nắm bắt bất kỳ nỗ lực nào để sử dụng phương thức với một lớp không có một hàm tạo tham số, miễn là loại được biết SOMEWHERE tại thời gian biên dịch, nó sẽ hoạt động và sẽ cảnh báo bạn vấn đề trước đó. Tất nhiên nếu loại thực sự chỉ được biết khi chạy (tức là bạn đang sử dụng Activator.CreateInstance() để khởi tạo một đối tượng dựa trên một chuỗi hoặc một kiểu được xây dựng) thì điều này sẽ không giúp bạn. Tôi thường sử dụng sự phản chiếu như là lựa chọn cuối cùng tuyệt đối, bởi vì một khi bạn đã đi đến vùng đất năng động, bạn phải ở lại trong vùng đất năng động; nó thường khó khăn hoặc thậm chí còn lộn xộn hơn để tự động khởi tạo một cái gì đó và sau đó bắt đầu xử lý nó một cách tĩnh lặng.

+0

Thực tế, có một mẫu rất hữu ích để bắc cầu các vùng đất của lời gọi tĩnh và động: một lớp bộ nhớ đệm chung chung tĩnh (ví dụ: 'EqualityComparer.Default ']. Đối với bất kỳ kiểu 'T' nào, người ta chỉ phải sử dụng Reflection một lần để xây dựng một đối tượng có kiểu instance sẽ được biết đến tĩnh để đủ điều kiện cho bất kỳ ràng buộc bắt buộc nào và lưu trữ một tham chiếu đến nó trong một trường không áp đặt bất kỳ ràng buộc nào người gọi có thể không cung cấp được. – supercat

10
type.GetConstructor(Type.EmptyTypes) != null 

sẽ không thành công cho struct s. Tốt hơn để mở rộng nó:

public static bool HasDefaultConstructor(this Type t) 
{ 
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null; 
} 

Thành công kể từ khi enum s có hàm tạo tham số mặc định. Cũng tăng tốc nhẹ cho các loại giá trị kể từ khi cuộc gọi phản chiếu không được thực hiện.

1

Tôi cần tính các nhà thầu chỉ với chỉ thông số tùy chọn giống như các hàm tạo ít tham số thực.Để thực hiện việc này:

myClass.GetType().GetConstructors() 
    .All(c => c.GetParameters().Length == 0 || c.GetParameters().All(p => p.IsOptional)) 
Các vấn đề liên quan