2013-08-04 38 views
7

tôi cần phải viết một loạt các phương pháp chăm 1..N tham số kiểu chung chung, ví dụ:C# generics: bất kỳ cách nào để tham khảo các loại tham số chung chung như một bộ sưu tập?

int Foo<T1>(); 
int Foo<T1,T2>(); 
int Foo<T1,T2,T3>(); 
... 
int Foo<T1,T2,T3...TN>(); 

Bên Foo() Tôi muốn làm điều gì đó cho từng loại, ví dụ như

int Foo<T1,T2,T3>() { 
    this.data = new byte[3]; // allocate 1 array slot per type 
} 

Is có cách nào để tham số hóa thông tin này để tôi không chỉnh sửa mọi biến thể của Foo(), tương tự như:

int Foo<T1,T2,T3>() { 
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS]; 
} 

Lý tưởng nhất, tôi cũng muốn để có thể nhận được một mảng hoặc bộ sưu tập các loại cũng như:

int Foo<T1,T2,T3>() { 
    this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS]; 

    // can do this 
    Type [] types = new Type[] { T1, T2, T3 }; 
    // but would rather do this 
    Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS; 
} 
+0

Nó không thực sự có ý nghĩa trong ngữ cảnh của hệ thống kiểu C# để có danh sách tham số chung VARdic - làm cách nào bạn tạo một phương thức với các kiểu đó trong chữ ký của nó? Và nếu bạn không bao giờ sử dụng các tham số kiểu trong một chữ ký phương thức, nó sẽ thích hợp hơn khi chỉ sử dụng một tập hợp 'Loại' trực tiếp. (Trừ khi bạn đang cố gắng nắm bắt các kiểu biên dịch của danh sách tham số variadic nhưng điều đó không thực sự hợp lý - danh sách 'params' là một mảng của một kiểu định sẵn.) – millimoose

+0

Hãy xem cái này, http : //stackoverflow.com/questions/44153/can-you-use-reflection-to-find-the-name-of-the-currently-executing-method, tuy nhiên tôi nghi ngờ nó rắc rối hơn nó đáng giá. –

+0

Hãy xem câu trả lời của Jon Skeet tại http://stackoverflow.com/questions/213333/using-c-sharp-params-keyword-in-a-constructor-of-generic-types. Bạn có thể sử dụng từ khóa params, tùy thuộc vào nhu cầu của bạn. – Kirk

Trả lời

8

Bạn có thể đọc các tham số chung hiện tại và số của chúng từ MethodInfo.GetGenericArguments array.

Bạn có thể truy xuất MethodInfo cho phương pháp hiện tại của mình bằng cách sử dụng MethodBase.GetCurrentMethod method. Lưu ý rằng bạn vẫn sẽ cần phải cung cấp một số quá tải chung của phương pháp của bạn với các số khác nhau của các tham số chung, như C# và CLI không hỗ trợ các danh sách tham số chung VARdic.

Vì vậy, mẫu mã của bạn cho các phương pháp với ba thông số chung có thể được viết như thế này:

int Foo<T1,T2,T3>() { 
    MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod(); 
    Type[] types = mInfo.GetGenericArguments(); 

    this.data = new byte[types.Length]; 
} 
+0

Cảm ơn bạn! (Tôi nghĩ rằng có một lỗi đánh máy trong trả lời của bạn-nó phải được GetGenericArguments() thay vì GenericTypeArguments()) – CoderBrien

+0

@CoderBrien: Bạn đang phải - 'GenericTypeArguments' tồn tại cho lớp' Type'. Đã sửa. –

+0

Tôi biết bạn đang cố gắng tránh đặt 'loại' và' dữ liệu' "tĩnh", tức là sử dụng thông tin bạn có lúc biên dịch, nhưng lưu ý rằng cách tiếp cận này chuyển gánh nặng thành thời gian chạy; đó là, cách tiếp cận năng động này bằng cách sử dụng Reflection có một hiệu suất nhấn mà phương pháp tiếp cận tĩnh không có (vì trình biên dịch sẽ làm tất cả những công việc đó). – stakx

0

số Bạn không thể sử dụng tham số Kiểu như bạn muốn. Nhưng bạn có thể sử dụng một cái gì đó như Tuple. Nó cho phép bạn Wrap generics. Nhưng bạn không thể sử dụng chính TypeParamter.

2

1) Bạn có thể nhận được số lượng đối số mẫu thông qua phản ánh: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx. Bằng cách này, bạn có thể thực hiện phổ biến cho mỗi Foo. Trong mỗi Foo bạn chỉ có thể gọi:

FooImpl(); 

Sự khác biệt duy nhất (liên quan đến việc "GetCurrentMethod") là bạn sẽ cần phải nhận được thông tin phương pháp của phương pháp trước đó:

StackTrace stackTrace = new StackTrace(); 
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod(); 

2) Bạn có thể tạo ra tất cả các phiên bản Foo trong thời gian chạy - tất cả sẽ chia sẻ cùng một triển khai chỉ gọi FooImpl. Một số chi tiết về phương pháp tạo khi chạy: Creating a function dynamically at run-time và tại đây: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx

1

Khuôn khổ .NET liên quan đến một lớp chung hoặc phương thức có tham số loại N có tên khác với tên có nhiều hoặc ít hơn. Nó có lẽ sẽ là tốt mà không có sự thay đổi rất lớn cho khuôn khổ để sắp xếp mọi thứ để gọi một hàm

foo<T>(autogeneric ref T it) 

như:

foo(1, "George", 5.7); 

sẽ nhận được dịch như:

struct foo99 {public int p1; public string p2; public double p3}; 
... 
foo99 temp99; 
temp99.p1 = 1; 
temp99.p2 = "George"; 
temp99.p3 = 5.7; 
foo1(ref temp); 

Đó sẽ cho phép một phương pháp chung để chấp nhận hiệu quả một số lượng tham số tùy ý.Việc có thể truyền cấu trúc ẩn danh như vậy bởi ref có thể không có vẻ hữu ích, nhưng nó có thể rất mạnh khi kết hợp với lambdas.

Thông thường, việc đóng các biến cục bộ trong biểu thức lambda sẽ yêu cầu nâng các biến cục bộ vào đối tượng heap và xây dựng đại biểu nhắm mục tiêu đối tượng heap đó. Nếu người ta có thể sử dụng kiểu trên, người ta có thể thay vì tạo một đối tượng đóng cửa liên tục và một đại biểu và chuyển giao người đại diện, đơn giản là hoist các biến thích hợp vào một cấu trúc và chuyển một byref đến nó cùng với một ủy nhiệm tĩnh. Điều này sẽ chỉ hoạt động trong trường hợp thói quen được gọi sẽ không phải duy trì việc đóng cửa đã được thông qua, nhưng ở phía bên kia người gọi sẽ biết rằng thường lệ được gọi là sẽ không được kiên trì đóng cửa. Hơn nữa, trong khi không có ngôn ngữ .NET nào hỗ trợ một điều như vậy và một số thay đổi khung có thể được yêu cầu để cho phép mã thực hiện điều này dễ bay hơi, bằng cách tham chiếu một cấu trúc mà một số thành viên của chúng cũng là byrefs có thể làm cho lambda truy cập các tham số ref của thủ tục kèm theo - một thứ mà hiện tại không thể thực hiện được (vì không có đảm bảo rằng đại biểu được tạo sẽ không vượt quá phạm vi mà nó được tạo). Các cấu trúc chết khi phạm vi chúng chết, vì vậy vấn đề sẽ không tồn tại với chúng.

Tôi muốn ngôn ngữ .NET có cách thuận tiện để thể hiện các khái niệm này. Thực tế là các bao đóng có thể làm cho các vòng đời của các biến được tùy ý tồn tại có nghĩa là mã đã từng sử dụng một biến trong một bao đóng phải giả định rằng mã bên ngoài có thể thay đổi nó bất cứ lúc nào. Một cách tiếp cận dựa trên cấu trúc sẽ không có vấn đề đó.

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