2012-10-25 11 views
10

tôi có mã này cho C# trong Visual Studio 2012.Vượt qua một đối số cho tác vụ trong C++/CLI?

public Task SwitchLaserAsync(bool on) 
{ 
    return Task.Run(new Action(() => SwitchLaser(on))); 
} 

này sẽ thực hiện phương pháp SwitchLaser (thành viên không tĩnh công cộng của một lớp MyClass) như là một nhiệm vụ với lập luận bool trên.

Tôi muốn làm điều gì đó tương tự trong quản lý C++/CLI. Nhưng tôi không thể tìm ra bất kỳ cách nào để chạy một nhiệm vụ, mà sẽ thực hiện một phương pháp thành viên tham gia một tham số.

giải pháp hiện tại là như thế này:

Task^ MyClass::SwitchLaserAsync(bool on) 
{ 
    laserOn = on; //member bool 
    return Task::Run(gcnew Action(this, &MyClass::SwitchLaserHelper)); 
} 

Thực hiện SwitchLaserHelper chức năng:

void MyClass::SwitchLaserHelper() 
{ 
    SwitchLaser(laserOn); 
} 

Phải có một số giải pháp như trong C# và không để tạo ra các chức năng helper và các thành viên (đây không phải là thread-).

Trả lời

10

Chưa có cách nào để thực hiện việc này.

Trong C#, bạn đóng cửa. Khi trình biên dịch C++/CLI của bạn được viết, cú pháp chuẩn hóa cho các bao đóng trong C++ vẫn đang được thảo luận. Rất may, Microsoft đã chọn để chờ đợi và sử dụng cú pháp lambda tiêu chuẩn thay vì giới thiệu một cú pháp duy nhất khác. Thật không may, nó có nghĩa là tính năng này chưa có sẵn. Khi nó là, nó sẽ giống như thế:

gcnew Action([on](){ SwitchLaserHelper(on) }); 

Giải pháp threadsafe hiện nay là để làm những gì # trình biên dịch C không - đặt các chức năng helper và các thành viên dữ liệu không vào lớp học hiện tại, nhưng vào một subtype lồng nhau. Tất nhiên bạn sẽ cần phải lưu con trỏ this ngoài biến cục bộ của bạn.

ref class MyClass::SwitchLaserHelper 
{ 
    bool laserOn; 
    MyClass^ owner; 

public: 
    SwitchLaserHelper(MyClass^ realThis, bool on) : owner(realThis), laserOn(on) {} 
    void DoIt() { owner->SwitchLaser(laserOn); } 
}; 

Task^ MyClass::SwitchLaserAsync(bool on) 
{ 
    return Task::Run(gcnew Action(gcnew SwitchLaserHelper(this, on), &MyClass::SwitchLaserHelper::DoIt)); 
} 

Cú pháp C++ lamdba sẽ đơn giản tạo lớp trợ giúp cho bạn (hiện tại nó hoạt động cho lambdas bản địa, nhưng chưa làm việc cho các trình quản lý gốc).

+0

Cảm ơn câu trả lời. Rõ ràng lambda không được hỗ trợ trong mã được quản lý. Tôi vẫn muốn tránh tạo ra các lớp trợ giúp. Những gì tôi đã tìm thấy trong tài liệu là lớp Action cho quản lý C++. Điều này sẽ có khả năng để có một chức năng với một đối số nhưng tôi đã không thể sử dụng nó và đặc biệt là với một phương pháp Task :: Run (hoặc bằng cách nào đó sử dụng nó với một lớp Task). Có một giải pháp mà không có một lớp trợ giúp hoặc phương pháp trợ giúp? – Bezousek

+0

@Bezousek: 'Tác vụ :: Run' yêu cầu ủy nhiệm' Tác vụ'. Không, một 'Action ' không phải là cùng một loại. Các đóng được thực hiện với một lớp trợ giúp. Đây là những gì trình biên dịch C# tạo ra từ mã ví dụ của bạn trong câu hỏi của bạn, và đây là những gì trình biên dịch C++/CLI sẽ làm một ngày nào đó nếu các tính năng lambda được quản lý được thêm vào. –

3

Đây là mã chung tôi đã viết chiều nay có thể giúp (mặc dù nó không phải là một kết hợp chính xác cho câu hỏi này). Có lẽ điều này sẽ giúp người tiếp theo tình cờ gặp câu hỏi này.

generic<typename T, typename TResult> 
ref class Bind1 
{ 
    initonly T arg; 
    Func<T, TResult>^ const f; 
    TResult _() { return f(arg); } 

public: 
    initonly Func<TResult>^ binder; 
    Bind1(Func<T, TResult>^ f, T arg) : f(f), arg(arg) { 
     binder = gcnew Func<TResult>(this, &Bind1::_); 
    } 
}; 

ref class Binder abstract sealed // static 
{ 
public: 
    generic<typename T, typename TResult> 
    static Func<TResult>^ Create(Func<T, TResult>^ f, T arg) { 
     return (gcnew Bind1<T, TResult>(f, arg))->binder; 
    } 
}; 

Cách sử dụng

const auto f = gcnew Func<T, TResult>(this, &MyClass::MyMethod); 
return Task::Run(Binder::Create(f, arg)); 
0

Tôi đã có một vấn đề tương tự khi tôi muốn cung cấp một tham số để một nhiệm vụ thực hiện một phương pháp mà không trả lại một giá trị (retuns void). Do đó, Func<T, TResult> không phải là một tùy chọn mà tôi có thể sử dụng. Để biết thêm thông tin, vui lòng kiểm tra trang Using void return types with new Func.

Vì vậy, tôi đã kết thúc với một giải pháp mà tôi đã tạo ra một lớp helper

template <typename T> 
ref class ActionArguments 
{ 
public: 
    ActionArguments(Action<T>^ func, T args) : m_func(func), m_args(args) {}; 
    void operator()() { m_func(m_args); }; 

private: 
    Action<T>^ m_func; 
    T m_args; 
}; 

được sử dụng Action<T> đại biểu để đóng gói một phương pháp mà có một tham số duy nhất và không trả lại một giá trị.

Sau đó tôi sẽ sử dụng lớp helper này trong cách sau

ref class DisplayActivationController 
{ 
public: 
    DisplayActivationController(); 

    void StatusChanged(EventArgs^ args) { }; 
} 


Action<EventArgs^>^ action = 
    gcnew Action<EventArgs^>(this, &DisplayActivationController::StatusChanged); 
ActionArguments<EventArgs^>^ action_args = 
    gcnew ActionArguments<EventArgs^>(action, args); 
Threading::Tasks::Task::Factory-> 
    StartNew(gcnew Action(action_args, &ActionArguments<EventArgs^>::operator())); 

Cách tiếp cận sử dụng các lớp helper có lẽ không phải là giải pháp thanh lịch nhất, nhưng là tốt nhất tôi có thể tìm được sử dụng trong C++/CLI không hỗ trợ các biểu thức lambda.