2010-03-16 9 views
6

Tôi đang tạo một chương trình di truyền, nhưng tôi nhấn một giới hạn với C# nơi tôi muốn trình bày các hàm mới cho thuật toán nhưng tôi không thể thực hiện nó mà không biên dịch lại chương trình. Về bản chất tôi muốn người dùng của chương trình cung cấp các chức năng được phép và GP sẽ tự động sử dụng chúng. Nó sẽ là tuyệt vời nếu người dùng được yêu cầu phải biết càng ít về lập trình càng tốt.C# cách tạo các hàm được diễn giải tại thời gian chạy

Tôi muốn cắm các chức năng mới mà không cần biên dịch chúng vào chương trình. Trong Python, điều này là dễ dàng, vì nó đã được giải nghĩa, nhưng tôi không có đầu mối làm thế nào để làm điều đó với C#. Có ai biết làm thế nào để đạt được điều này trong C#? Có thư viện, kỹ thuật nào không?

+2

điều này không hoàn toàn trả lời câu hỏi của bạn, nhưng vì bạn đang sử dụng .net, bạn có thể sử dụng F # cho phần đó của ứng dụng, vì nó có thể được hiểu tại thời gian chạy – andy

Trả lời

13

Tùy thuộc vào cách bạn muốn người dùng chương trình "cung cấp các chức năng được cho phép".

  • Nếu người dùng đang chọn các chức năng mà bạn đã triển khai, bạn có thể chuyển những thứ này dưới dạng đại biểu hoặc cây biểu thức.
  • Nếu người dùng sẽ viết các phương thức riêng của họ bằng ngôn ngữ C# hoặc ngôn ngữ .NET khác và biên dịch chúng thành một assembly, bạn có thể tải chúng bằng cách sử dụng Reflection.
  • Nếu bạn muốn người dùng có thể nhập mã nguồn C# vào chương trình của bạn, bạn có thể biên dịch mã nguồn đó bằng cách sử dụng CodeDom, sau đó gọi kết quả bằng cách sử dụng Reflection.
  • Nếu bạn muốn cung cấp ngôn ngữ biểu thức tùy chỉnh cho người dùng, ví dụ: một ngôn ngữ toán học đơn giản, sau đó (giả sử bạn có thể phân tích ngôn ngữ), bạn có thể sử dụng Reflection.Emit để tạo ra một assembly động và gọi nó bằng cách sử dụng - bạn đoán nó - Reflection. Hoặc bạn có thể xây dựng một cây biểu thức từ mã người dùng và biên dịch sử dụng LINQ - phụ thuộc vào mức độ linh hoạt mà bạn cần. (Và nếu bạn có thể đủ khả năng để chờ đợi, biểu hiện cây trong .NET 4.0 loại bỏ nhiều hạn chế trong 3.5, vì vậy bạn có thể tránh Reflection.Emit hoàn toàn.)
  • Nếu bạn hài lòng cho người dùng nhập các biểu thức sử dụng Python, Ruby hoặc một ngôn ngữ DLR khác, bạn có thể lưu trữ Thời gian chạy ngôn ngữ động, sẽ giải thích mã của người dùng cho bạn.

Lưu trữ DLR (và IronPython hoặc IronRuby) có thể là lựa chọn tốt ở đây vì bạn có môi trường được kiểm tra tốt và tất cả các tối ưu mà DLR cung cấp.Here's a how-to using IronPython.

Đã thêm vào câu trả lời cho câu hỏi hiệu suất của bạn: DLR là thông minh hợp lý về tối ưu hóa. Nó không tái diễn giải mã nguồn một cách mù quáng mỗi lần: một khi nó đã chuyển mã nguồn (hoặc, cụ thể là một hàm hoặc lớp đã cho) thành MSIL, nó sẽ tiếp tục sử dụng lại biểu diễn đã biên dịch cho đến khi mã nguồn thay đổi (ví dụ: chức năng được định nghĩa lại). Vì vậy, nếu người dùng tiếp tục sử dụng cùng một chức năng nhưng trên các tập dữ liệu khác nhau, thì miễn là bạn có thể giữ cùng một ScriptScope xung quanh, bạn sẽ nhận được sự hoàn hảo tốt; ditto nếu mối quan tâm của bạn chỉ là bạn sẽ chạy cùng một hàm zillions của thời gian trong thuật toán di truyền. Lưu trữ DLR là khá dễ dàng để làm, vì vậy nó không phải là khó khăn để làm một bằng chứng về khái niệm và biện pháp để xem nếu nó lên đến nhu cầu của bạn.

+0

Tôi thích các tùy chọn phản chiếu mà bạn đã đề cập ... chúng có thể là lựa chọn tốt nhất của tôi. DLR có thể là một lựa chọn tốt, có chi phí hiệu năng đáng kể khi gọi phương thức DLR không? Các phương thức sẽ được gọi RẤT thường xuyên, vì vậy tôi muốn sử dụng một tùy chọn có ít chi phí nhất có thể. – Kiril

+0

Tôi đã thêm một số thông tin về cách DLR cải thiện hiệu suất với mã được gọi lặp lại. Tôi không có số liệu định lượng mặc dù, nhưng bạn có thể tìm thấy một cái gì đó trên Google, hoặc thất bại mà nó khá dễ dàng để lưu trữ các DLR và cung cấp cho nó một cách nhanh chóng đi. – itowlson

+0

Yah, tôi không có kế hoạch sửa đổi mã nguồn trong khi thực thi nó có thể sẽ là cùng một phương pháp nhưng với một cá thể dữ liệu khác nhau, vì vậy DLR có thể là một lựa chọn tốt. Tôi cũng sẽ sử dụng tính năng ghi nhớ, vì vậy nếu các tham số giống nhau luôn tạo ra kết quả tương tự, thì phương thức sẽ không được thực thi một cách không cần thiết. Cảm ơn :). – Kiril

7

Bạn có thể thử tạo và thao tác Expression Trees. Sử dụng Linq để đánh giá các cây biểu thức.

+2

Cây biểu thức tuyến đường tốt hơn so với hàm eval thuần túy. –

+0

GP của tôi có nhiều cá nhân và mỗi cá nhân có một cây chức năng và hằng số. Một nút trong cây có thể là một hàm hoặc một hằng số ... điều đó có nghĩa là tôi nên thay thế hàm tại một nút đã cho bằng một cây biểu thức? Người dùng có thể cắm chức năng của họ như thế nào? – Kiril

+0

Lưu ý rằng cây không thực sự chứa hàm, mà là một enum xác định hàm. Khi được gọi là "thực thi" chỉ đơn giản là nhìn vào enum và gọi hàm tương ứng. – Kiril

1

Bạn có quyền truy cập Trình biên dịch từ bên trong mã, sau đó bạn có thể tạo các phiên bản của mã được biên dịch và sử dụng chúng mà không cần khởi động lại ứng dụng. Có những ví dụ của nó xung quanh

Here

Here

Điều thứ hai là một đánh giá javascript nhưng có thể được điều chỉnh dễ dàng đủ.

1

Bạn có thể xem System.Reflection.Emit để tạo mã ở cấp IL.

Hoặc tạo C#, biên dịch vào thư viện và tải động đó. Không gần như linh hoạt.