在C ++ / CLI中,将内部变量传递给委托的最简单方法是什么?

时间:2017-03-27 18:35:46

标签: c++-cli

我正在尝试设置一个将局部变量作为参数的委托。声明如下:

ref class Main
{
private:
    Func<String^>^ _expensiveMethodDelegate;

public:
    property Func<String^>^ ExpensiveMethodDelegate
    {
        Func<String^>^ get() { return this->_expensiveMethodDelegate; }
        void set(Func<String^>^ value) { this->_expensiveMethodDelegate = value; }
    };

    void DoWork()
    {
        String^ result = this->_expensiveMethodDelegate();
        Debug::WriteLine(result);
    }
};

在C#中,代码如下所示:

string parameter = "value";

Main main = new Main();
main.ExpensiveMethodDelegate = () =>
{
    Thread.Sleep(1000); // do expensive work
    return parameter + "1";
};

main.DoWork();

使用托管C ++(VS 2015)实现此目标的最简单方法是什么?注意:我阅读了文章Workaround for not having lambdas that can capture managed variablesLambda expressions as CLR (.NET) delegates / event handlers in Visual C++ 2010,但仍然无法弄清楚解决方案是什么。

我尝试了这样的代码(使用第二篇文章中的make_delegate),但无法编译:

String^ parameter = L"value";

Main^ main = gcnew Main();
main->ExpensiveMethodDelegate = make_delegate(
    [](String^ parameter) -> String^
    {
        Threading::Thread::Sleep(1000); // do work
        return parameter + L"1";
    });

main->DoWork();

1 个答案:

答案 0 :(得分:0)

这就是我提出的:

#pragma once

#include <new>

using namespace std::tr1;
using namespace System;

namespace helper
{
    private struct return_type_helper
    {
    private:

        template<class D>
        struct dependent_false { enum { value = false }; };

        template <class D>
        struct illegal_delegate_type
        {
            static_assert(dependent_false<D>::value, "Delegates with more than 2 parameters, or with parameters of tracking reference types (T%), are not supported.");
        };

        struct anything
        {
            template<class T>
            operator T() const;
        };

    public:
        template<class D>
        static decltype(static_cast<D^>(nullptr)(anything())) dummy(int(*)[2]);

        template<class D>
        static decltype(static_cast<D^>(nullptr)(anything(), anything())) dummy(int(*)[3]);
    };

    template<class Func, class Aligner = char, bool Match = (alignment_of<Func>::value == alignment_of<Aligner>::value)>
    struct aligner
    {
        static_assert(Match, "Function object has unsupported alignment");
    };

    template<class Func, class Aligner>
    private struct aligner<Func, Aligner, true>
    {
        typedef Aligner type;
    };

    template<class F>
    private ref class lambda_wrapper
    {
    public:
        lambda_wrapper(const F& f)
        {
            pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
            new(pf) F(f);
        }

        ~lambda_wrapper()
        {
            pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
            pf->~F();
        }

        template <class D>
        operator D ^ ()
        {
            D^ d = nullptr;
            return gcnew D(this, &lambda_wrapper<F>::invoke<decltype(return_type_helper::dummy<D>(0))>);
        }

    private:
        template<class T>
        [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential, Size = sizeof(T))]
        value struct embedded_storage
        {
        private:
            typename aligner<T>::type dummy;
        };

        embedded_storage<F> f_storage;

        template<class R, class A1>
        R invoke(A1 a1)
        {
            pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
            return (*pf)(a1);
        }

        template<class R, class A1, class A2>
        R invoke(A1 a1, A2 a2)
        {
            pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
            return (*pf)(a1, a2);
        }
    };

    template <typename...>
    ref class DelegateHelper;

    template<class TParam1, class TResult>
    ref class DelegateHelper<TParam1, TResult>
    {
    private:
        Func<TParam1, TResult>^ _lambda;
        TParam1 _param1;

        TResult Execute()
        {
            return this->_lambda(this->_param1);
        }

    public:
        template<class TLambda>
        DelegateHelper(TLambda lambda, TParam1 param1)
        {
            this->_lambda = gcnew helper::lambda_wrapper<TLambda>(lambda);
            this->_param1 = param1;
        }

        static operator Func<TResult> ^ (DelegateHelper<TParam1, TResult>^ value)
        {
            return gcnew Func<TResult>(value, &DelegateHelper<TParam1, TResult>::Execute);
        }
    };

    template<class TParam1, class TParam2, class TResult>
    ref class DelegateHelper<TParam1, TParam2, TResult>
    {
    private:
        Func<TParam1, TParam2, TResult>^ _lambda;
        TParam1 _param1;
        TParam2 _param2;

        TResult Execute()
        {
            return this->_lambda(this->_param1, this->_param2);
        }

    public:
        template<class TLambda>
        DelegateHelper(TLambda lambda, TParam1 param1, TParam2 param2)
        {
            this->_lambda = gcnew helper::lambda_wrapper<TLambda>(lambda);
            this->_param1 = param1;
            this->_param2 = param2;
        }

        static operator Func<TResult> ^ (DelegateHelper<TParam1, TParam2, TResult>^ value)
        {
            return gcnew Func<TResult>(value, &DelegateHelper<TParam1, TParam2, TResult>::Execute);
        }
    };
}

这是如何使用它:

String^ parameter1 = L"value1";
String^ parameter2 = L"value2";
Main^ main = gcnew Main();

auto lambda1 = [](String^ parameter) -> String^
{
    Threading::Thread::Sleep(1000);
    return parameter;
};

main->ExpensiveMethodDelegate = gcnew helper::DelegateHelper<String^, String^>(lambda1, parameter1);

main->DoWork();

auto lambda2 = [](String^ parameter1, String^ parameter2) -> String^
{
    Threading::Thread::Sleep(1000);
    return parameter1 + parameter2;
};

main->ExpensiveMethodDelegate = gcnew helper::DelegateHelper<String^, String^, String^>(lambda2, parameter1, parameter2);

main->DoWork();

不确定它是否是最优雅的方式,但它确实是我正在寻找的工作。