2010-04-09 30 views
9

Tôi có một phương pháp như sau:C# đèo Generics Tại Runtime

public IEnumerable<T> GetControls<T>() 
: where T : ControlBase 
{ 
// removed. 
} 

tôi sau đó tạo ra một lớp:

public class HandleBase<TOwner> : ControlBase 
: TOwner 
{ 
// Removed 
} 

Tôi muốn để có thể gọi

GetControls<HandleBase<this.GetType()>>; 

nơi nó sẽ sử dụng loại lớp THIS để chuyển sang HandleBase. Điều này về cơ bản sẽ có được tất cả các HandleBase có một chủ sở hữu của loại này.

Tôi làm cách nào để đạt được điều này?

EDIT:

Tôi đang sử dụng .NET 2.0 để các giải pháp lớn hơn 2.0 sẽ không hoạt động.

Ý tưởng là để ControlBase có một bộ sưu tập các ControlBase khác cho "trẻ em". Sau đó, họ có thể được truy vấn dựa trên loại của họ với GetControls<T>(). Điều này sẽ cho phép tôi, ví dụ, có được tất cả HandleBase cho một Shape. Sau đó, tôi có thể thực hiện tất cả những điều này và đặt Hiển thị = sai hoặc làm điều gì đó khác với chúng. Do đó tôi có thể điều khiển trẻ em thuộc một loại cụ thể cho một bộ sưu tập.

HandleBase<TOwner> yêu cầu TOwner vì nó có tham chiếu đến "loại sở hữu". Vì vậy, bạn chỉ có thể thêm bất cứ điều gì kéo dài HandleBase đến một hình dạng. Có lý?

Cảm ơn tất cả trợ giúp!

+2

@TheCloudlessSky, tại sao gọi 'this.GetType()'? nếu bạn đang gọi 'GetControls >();' từ một lớp dựa trên cá thể [như 'this' chỉ ra], tại sao không đơn giản sử dụng tên kiểu khai báo của lớp thực hiện? nếu đây là một lớp cơ sở, có nghĩa là để lộ loại của lớp con cho lớp cơ sở. –

+0

Xem chỉnh sửa ở trên. – TheCloudlessSky

Trả lời

0

Điều này cụ thể cho việc triển khai thực hiện điều này nhưng tôi đã có thể giải quyết vấn đề này bằng cách tạo một số không chung chung HandleBase trước và sau đó là chung HandleBase<TOwner>. Towner đã được sử dụng là chủ sở hữu tài sản.

Sau đó, khi tôi có thể gọi GetControls<HandleBase> và nhận tất cả HandleBase bất kể Chủ sở hữu.

Cảm ơn tất cả các câu trả lời!

2

Bạn không thể. Generics là một tính năng biên dịch thời gian. Bạn sẽ cần phải bao gồm các loại như là một tham số không chung chung cho phương pháp, và vượt qua nó trong đó.

+1

Bạn có thể sử dụng sự phản chiếu để làm điều đó. Nhưng điều đó thực sự có vẻ như quá mức cần thiết cho những gì được mô tả trong vấn đề. Tôi đồng ý với việc chuyển tham chiếu kiểu tới hàm thay thế. –

+0

System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); Loại t = a.GetType ("SeaSharpWinApp8.Program"); MethodInfo mi = t.GetMethod ("f", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miGeneric = mi.MakeGenericMethod (Loại mới [] {typeof (string)}); miGeneric.Invoke (null, đối tượng mới [] {"works"}); –

+0

Đó là cuộc gọi MakeGenericMethod cho phép bạn làm điều đó. Bạn phải lấy MethodInfo trước, sau đó lấy một cái khác với các kiểu cụ thể mà bạn muốn sử dụng. Nếu đó là loại chung thì bạn thực hiện cuộc gọi MakeGeneric * ở cấp loại thay thế. –

13

Bạn có thể thực hiện việc này bằng cách chỉ định loại tại thời gian biên dịch hoặc bằng cách sử dụng phản chiếu.

Bạn có thể làm điều đó với suy nghĩ như thế này:

typeof(SomeClass).GetMethod("GetControls") 
    .MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType())) 
    .Invoke(someObject, null); 

Lưu ý rằng nó sẽ trả về một object; bạn sẽ không thể truyền nó đến IEnumerable<T> (Trừ khi bạn biết những gì T là lúc biên dịch, trong trường hợp đó không có điểm). Bạn có thể truyền nó tới IEnumerable.

Tuy nhiên, đây là một ý tưởng tồi.
Có thể là giải pháp tốt hơn cho bạn; vui lòng cung cấp thêm chi tiết.

+0

là điều này có thể sử dụng sự phản ánh? ** Làm thế nào? ** – serhio

+3

Điều này có thể sử dụng sự phản chiếu, bằng cách gọi 'typeof (SomeClass) .GetMethod (" GetControls "). MakeGenericMethod (typeof (HandleBase <>). MakeGenericType (GetType())). Gọi (someObject, null) ' – SLaks

+0

Tại sao điều này lại được giảm giá? – SLaks

1

Lưu ý rằng các thông số loại không phải là biến. Do đó, bạn không thể sử dụng một biến thay cho tham số kiểu.

Bạn có thể, tuy nhiên, làm được điều này thông qua phản ánh, hoặc bằng cách sử dụng một cấu trúc đặc biệt mà là khá hạn chế nhưng có thể giải quyết trường hợp của bạn:

public class MyClass<TSelf> where TSelf: MyClass<TSelf> { 
    public IEnumerable<T> GetControls<T>() where T: ControlBase { 
    // removed. 
    } 

    public void MyCall() { 
     GetControls<HandleBase<TSelf>>(); 
    } 
} 

public class MyConcreteClass: MyClass<MyConcreteClass> { 
} 
0

Có lẽ không có cách nào để làm những gì bạn yêu cầu. Mở rộng ví dụ của bạn:

X x = GetControls<HandleBase<this.GetType()>>; 

Loại X nên ở đây? Tuy nhiên, từ các thông tin cơ bản khác, có vẻ như bạn cần có danh sách tất cả các điều khiển của kiểu đã cho.Ví dụ: bạn có thể thực hiện việc này theo cách như vậy:

public IEnumerable<ControlBase> GetControls(Type type) { 
//your logic here 
} 

Tùy thuộc vào các tập quán và mục tiêu khác của bạn, bạn cũng có thể muốn trả lại không chung chung cho IEnumerable.

0

Kể từ GetControls() trả về một liệt kê, bạn có thể tìm thấy một cách để lọc các kết quả liệt kê với .OfType <T>, một cái gì đó giống như

List<T2> list = controlList.GetControls<T>().OfType<T2>().ToList(); 

Bạn sẽ cần một hạn chế chung somehwere dọc theo dòng của

where T2 : T 
+0

Cụ thể là> = 3.0, tôi quên đề cập đến tôi đang sử dụng 2.0. – TheCloudlessSky