2009-12-05 8 views
123

Trong C# bạn có thể đặt một hạn chế trên một phương pháp chung chung như:Có một hàm tạo chung với ràng buộc tham số trong C# không?

public class A { 

    public static void Method<T> (T a) where T : new() { 
     //...do something... 
    } 

} 

đâu bạn xác định rằng T nên có một nhà xây dựng mà không cần tham số. Tôi đang tự hỏi liệu có một cách để thêm một hạn chế như

Các mã sau đây không biên dịch "tồn tại một nhà xây dựng với một tham số float[,]?":

public class A { 

    public static void Method<T> (T a) where T : new(float[,] u) { 
     //...do something... 
    } 

} 

Một cách giải quyết cũng là hữu ích?

+0

bản sao có thể có của [Làm cách nào để hạn chế loại chung phải có một construtor có tham số nhất định?] (Http://stackoverflow.com/questions/853703/how-to-constrain-generic-type-to -một-có-một-construtor-đó-mất-nhất định-param) – nawfal

Trả lời

115

Như bạn đã thấy, bạn không thể làm điều này.

Là một workaround tôi thường cung cấp một đại biểu có thể tạo các đối tượng của loại T:

public class A { 

    public static void Method<T> (T a, Func<float[,], T> creator) { 
     //...do something... 
    } 

} 
+37

là những hạn chế của các nhà xây dựng tham số vắng mặt vì một lý do logic, hay nó chỉ là một thứ chưa được thêm vào ngôn ngữ? –

+18

Đồng ý ...chúng ta nên có 'mới (float, double)', 'new (string)', v.v. – SliverNinja

+8

@Sahuagin Tôi nghĩ rằng không thể làm được vì khi bạn kế thừa từ một lớp, không có gì đảm bảo rằng sub-class có constructor được định nghĩa, vì các hàm tạo không được kế thừa. Mỗi lớp có một hàm tạo tham số rỗng. – Matthew

5

Không. Hiện tại, ràng buộc hàm tạo duy nhất mà bạn có thể chỉ định là cho một hàm tạo no-arg.

39

Không có cấu trúc nào như vậy. Bạn chỉ có thể chỉ định một ràng buộc constructor rỗng.

Tôi giải quyết vấn đề này với các phương thức lambda.

public static void Method<T>(Func<int,T> del) { 
    var t = del(42); 
} 

Trường hợp sử dụng

Method(x => new Foo(x)); 
+0

Không có cách nào để trừu tượng việc tạo ra 'Foo' bên trong' Phương thức'? –

+0

Điều gì sẽ xảy ra nếu người sử dụng 'Method' thực hiện' Method (x => new Foo()); '? Có anyway để đảm bảo rằng lambda nên được như thế? –

15

Dưới đây là một cách giải quyết cho điều này mà cá nhân tôi thấy khá hiệu quả. Nếu bạn nghĩ về ràng buộc constructor được tham số hóa chung là gì, nó thực sự là một ánh xạ giữa các kiểu và các hàm tạo với một chữ ký cụ thể. Bạn có thể tạo ánh xạ như vậy bằng cách sử dụng từ điển. Đặt chúng trong một lớp học "nhà máy" tĩnh và bạn có thể tạo các đối tượng của loại hình khác nhau mà không cần phải lo lắng về việc xây dựng một nhà xây dựng lambda mỗi lần:

public static class BaseTypeFactory 
{ 
    private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2); 

    private static readonly Dictionary<Type, BaseTypeConstructor> 
    mTypeConstructors = new Dictionary<Type, BaseTypeConstructor> 
    { 
     { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) }, 
     { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) }, 
     { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) } 
    }; 

sau đó trong phương pháp chung của bạn, ví dụ:

public static T BuildBaseType<T>(...) 
     where T : BaseType 
    { 
     ... 
     T myObject = (T)mTypeConstructors[typeof(T)](value1, value2); 
     ... 
     return myObject; 
    } 
+1

tại sao điều này xứng đáng với ngón tay cái xuống? nó hoạt động rất tốt trong kinh nghiệm của tôi. –

+1

Tôi đang sử dụng này ngay bây giờ, tôi nghĩ rằng đó là một mô hình tốt. Hoạt động thực sự tốt với mẫu Nhà máy. Cảm ơn! – Matthew

32

Sử dụng phản chiếu để tạo đối tượng chung, loại vẫn cần hàm dựng đúng được khai báo hoặc một ngoại lệ sẽ được ném. Bạn có thể vượt qua bất kỳ đối số nào miễn là chúng khớp với một trong các hàm tạo.

Được sử dụng theo cách này bạn không thể đặt ràng buộc vào hàm tạo trong mẫu. Nếu hàm khởi tạo bị thiếu, một ngoại lệ cần được xử lý tại thời gian chạy thay vì nhận được lỗi tại thời gian biên dịch.

// public static object CreateInstance(Type type, params object[] args); 

// Example 1 
T t = (T)Activator.CreateInstance(typeof(T)); 
// Example 2 
T t = (T)Activator.CreateInstance(typeof(T), arg0, arg1, arg2, ...); 
// Example 3 
T t = (T)Activator.CreateInstance(typeof(T), (string)arg0, (int)arg1, (bool)arg2);