2009-07-03 41 views
6

Có thể thậm chí không thể thực hiện việc này, nhưng tôi vẫn sẽ hỏi. Có thể tạo ra một hàm nhận chuỗi và sau đó sử dụng nó làm đối số bên phải cho toán tử đi vào (=>) được sử dụng trong lambda không?Tạo chức năng tự động tại thời gian chạy

Thực ra, những gì tôi muốn làm là để có thể xác định lại một phương pháp cụ thể của một lớp cụ thể trong thời gian chạy. Tôi muốn viết ra một hàm với chương trình đang chạy và đính kèm nó vào một đại biểu. Có thể không?

+0

Bạn có thể cho chúng tôi biết trường hợp sử dụng thực tế của bạn là gì? Có thể có một số cách khác để giải quyết yêu cầu của bạn. – SolutionYogi

+0

Nếu tôi đọc chính xác, bạn muốn eval() một chuỗi? http://en.wikipedia.org/wiki/Eval – Stobor

Trả lời

8

Cách dễ nhất để làm điều đó có thể là DLINQ như TcK đề xuất.

Nhanh nhất (tôi tin rằng, trong 3.5) là tạo một DynamicMethod. Nó cũng là phương pháp đáng sợ nhất. Về cơ bản, bạn đang xây dựng một phương pháp sử dụng IL, có cảm giác giống như viết mã bằng ngôn ngữ máy.

Tôi cần thực hiện điều này để tự động đính kèm trình xử lý sự kiện trong một số điều hay cách khác (tốt, tôi không cần phải làm điều đó, tôi chỉ muốn thực hiện các sự kiện kiểm tra đơn vị dễ dàng hơn). Nó có vẻ hơi khó khăn vào thời điểm đó bởi vì tôi không biết crap về IL, nhưng tôi đã tìm ra một cách đơn giản để thực hiện điều này.

Việc bạn làm là tạo phương thức thực hiện chính xác những gì bạn muốn. Càng gọn thì càng tốt. Tôi sẽ cung cấp một ví dụ nếu tôi có thể tìm ra chính xác những gì bạn đang cố gắng làm. Bạn viết phương thức này trong một lớp trong một dự án DLL và biên dịch nó trong chế độ phát hành. Sau đó, bạn mở DLL trong Reflector và tháo rời phương thức của bạn. Reflector cho bạn tùy chọn ngôn ngữ mà bạn muốn tháo rời - chọn IL. Bây giờ bạn có các cuộc gọi chính xác mà bạn cần phải thêm vào phương thức động của mình. Chỉ cần làm theo ví dụ trên MSDN, chuyển đổi IL của ví dụ cho mã phương thức được phản ánh của bạn.

Phương pháp động, khi được xây dựng, gọi ở tốc độ tương tự như phương pháp được biên dịch (xem thử nghiệm nơi phương pháp động có thể được gọi trong ~ 20ms nơi phản ánh mất hơn 200 mili giây).

+0

WoW, và ở đây tôi nghĩ rằng tôi đã biết điều gì đó về .NET. Và tôi chưa từng nghe về nó. Tôi sợ hỏi làm thế nào bạn có bao giờ quản lý để vấp ngã khi tính năng như vậy. –

+0

DynamicMethod có sẵn từ 2.0 – flq

5

Câu hỏi của bạn khá không rõ ràng, nhưng bạn chắc chắn có thể sử dụng cây biểu thức để tạo đại biểu động tại thời gian thực thi. (Có nhiều cách khác để thực hiện nó như CodeDOM, nhưng các cây biểu hiện là handier nếu chúng thực hiện tất cả những gì bạn cần. Tuy nhiên, có những hạn chế đáng kể đối với những gì bạn có thể làm)

Thường dễ dàng hơn khi sử dụng lambda biểu hiện với một số biến bị bắt mặc dù.

Ví dụ, để tạo một hàm mà sẽ bổ sung thêm các khoản tiền nhất định cho bất kỳ số nguyên, bạn có thể viết:

static Func<int, int> CreateAdder(int amountToAdd) 
{ 
    return x => x + amountToAdd; 
} 

... 
var adder = CreateAdder(10); 
Console.WriteLine(adder(5)); // Prints 15 

Nếu điều này không giúp đỡ, xin vui lòng làm rõ câu hỏi của bạn.

8

Bạn có nhiều cách làm thế nào để làm điều đó:

+0

Tôi ước tôi có thể chọn cả hai câu trả lời là câu trả lời đúng. Cả hai đều cung cấp cho tôi các giải pháp rất tốt. Và ở đây tôi nghĩ rằng nó sẽ là không thể. Bây giờ, Strategy Pattern không phải là thứ tôi đang tìm kiếm. Để sử dụng Chiến lược, tôi phải triển khai các phương pháp để tôi có thể trao đổi chúng. –

3

Không phải là tôi đang đề xuất này trong tốt hơn lựa chọn khác, nhưng có một 7 thứ phương pháp và thật dễ dàng khi sử dụng AssemblyBuilder, ModuleBuilder, TypeBuilder, và MethodBuilder trong không gian tên System.Reflection.Emit để tạo ra một hội đồng năng động. Đây là voodoo tương tự như sử dụng DynamicMethod.

Ví dụ: bạn có thể sử dụng chúng để, khi chạy, tạo lớp proxy cho loại và ghi đè các phương thức ảo trên loại đó.

Để giúp bạn bắt đầu ở đây là một số mã ...

using System; 
using System.Reflection; 
using System.Reflection.Emit; 

var myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
     new AssemblyName("Test"), AssemblyBuilderAccess.RunAndSave); 
var myModule = myAssembly.DefineDynamicModule("Test.dll"); 
var myType = myModule.DefineType("ProxyType", TypeAttributes.Public | TypeAttributes.Class, 
         typeof(TypeToSeverelyModifyInAnUglyWayButItsNecessary)); 
var myMethod = myType.DefineMethod("MethodNameToOverride", 
         MethodAttributes.HideBySig | MethodAttributes.Public, 
         typeof(void),Type.EmptyTypes); 
var myIlGenerator = myMethod.GetILGenerator(); 
myIlGenerator.Emit(OpCodes.Ret); 
var type = myType.CreateType(); 
+0

Dường như mất khoảng cùng một mã số mã để hoàn thành hơn là chỉ sử dụng DynamicMethod. Có bất kỳ lý do để sử dụng nó trên DynamicMethod? Nếu Will là đúng, DynamicMethods là gần như nhanh như mã biên dịch (mặc dù 20ms là một cõi đời đời trong thời gian máy tính). –

+0

Chỉ thực sự 'lợi thế' để sử dụng phương pháp này trên năng động là bạn có thể lưu các hội đồng tạo ra và bạn có thể kế thừa từ các loại và ghi đè lên các phương pháp ảo/tài sản. Hi vọng điêu nay co ich. Một lần nữa, tôi không đề xuất điều này để tiêu thụ chung, chỉ cần chỉ ra một tùy chọn khác. Khi bạn nói rằng bạn cần phải 'xác định lại' một phương thức, tùy thuộc vào ý bạn, đây có thể là một lựa chọn tốt hơn vì bạn có thể tạo kiểu và ghi đè lên các phương thức cơ sở ... – Jake

0

Nếu bạn khai báo các phương pháp như ảo, bạn có thể sử dụng lâu đài của DynamicProxy để thay thế một động tạo ra (với một trong những khác phương pháp của câu trả lời) khi triển khai:

Castle DynamicProxy là thư viện để tạo các tệp .NET. Các đối tượng proxy cho phép các cuộc gọi đến các thành viên của một đối tượng bị chặn mà không sửa đổi mã của lớp. Cả hai lớp và giao diện đều có thể được ủy nhiệm, tuy nhiên chỉ có thể chặn các thành viên ảo.

+0

Tôi có xu hướng tránh sử dụng thư viện của bên thứ ba trong mã. Đó là để tránh vấn đề về khóa của nhà cung cấp. Tôi đã có vấn đề nghiêm trọng với điều đó trước đây khi tôi mã hóa trong Delphi. Ví dụ, tôi vừa chuyển từ sử dụng SQLite - mặc dù tôi rất thích nó - với SQLServer CE chỉ để ở lại hoàn toàn trong khung công tác. –

+2

Nó có lợi thế là nguồn mở, vì vậy bạn không phải là "bị khóa" như bạn sẽ có với một giải pháp thương mại. Đôi khi bạn chỉ cần cân nhắc những lợi thế của việc tái tạo lại bánh xe và thực sự hoàn thành công việc. – Jacob

0

Đoạn thứ hai trong câu hỏi của bạn cho thấy rằng thực sự những gì bạn có thể là sau rất đơn giản IOC (Inversion of Control)

Thay vì tuyên bố một thể hiện của lớp học của bạn, bạn khai báo một thể hiện của một giao diện và dựa trên về bất kỳ điều kiện nào bạn chọn, bạn sử dụng lớp ghi đè cụ thể với phương pháp chính xác trong đó. Hy vọng rằng có ý nghĩa.

+0

Không, không phải vậy. Những gì tôi muốn là để có thể sửa đổi một phương pháp của một lớp trong thời gian chạy đến một cái gì đó tôi sẽ được gõ trong thời gian chạy. Khá giống với một eval, ngoại trừ việc tôi không đơn giản muốn nó để đánh bại và chết. Tôi muốn nó vẫn còn gắn liền với một đại biểu cho đến khi tôi cần phải thay đổi nó một lần nữa. –

+0

Ah, ok, vì vậy ứng dụng của bạn có thể có một kiểu nhập văn bản cho phép bạn nhập một số mã để sửa đổi hành động của một hàm? –

1

Bạn nên kiểm tra xem liệu sự cố của bạn có thể được giải quyết bằng sự đa hình đơn giản trước không. Trừ khi bạn đang xác định khả năng tương tác trừu tượng với một ngôn ngữ khác hoặc chỉnh sửa trình biên dịch, cố gắng thay đổi phương thức trong thời gian chạy có lẽ là giải pháp sai cho vấn đề.

+0

Tôi đồng ý 100%, đây phải là lựa chọn đầu tiên. – Jake

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