微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C# 中的 Lambda 和 ref/out

如何解决C# 中的 Lambda 和 ref/out

我有一些从与通信总线接口的 DLL 导入的类似 set/get 函数。理想情况下,这些都应该共享一个相同的包装器,执行一些错误检查、互斥处理等。下面的代码片段是它的基本表示。它编译并且所有函数似乎都可以工作,除了 WrappedGet() 不修改引用的变量数据。想法?

        static UInt32 common_var = 0;

        // Reduce boilerplate by wrapping all calls to the DLL with this
        static private bool CommonWrapper<T1>(Action<T1> dll_function_handle,ref T1 data)
        {
            // Commmon code for mutex handling etc
            /// .... 
            
            // Call to function handle,sometimes data is in-parameter,other times out-param
            dll_function_handle(data);
            
            return true;
        }

        static private void DllSet(UInt32 data) { common_var = data; }
        static public void WrappedSet(UInt32 data) { CommonWrapper<UInt32>((UInt32 a) => DllSet(a),ref data); }

        static private void DllGet(ref UInt16 data){ data = 1234; }
        // WrappedGet does not modify argument "data" because of the lambda? What to do?
        static public void WrappedGet(ref UInt16 data) { CommonWrapper<UInt16>((UInt16 a) => DllGet(ref a),ref data); }

编辑:

这有效:

  static public void WrappedGet(ref UInt16 data) 
  {
       UInt16 local = 0;
       CommonWrapper<UInt16>((UInt16) => DllGet(ref local),ref data);
       data = local;
  }

虽然有点尴尬,这样做是否正确?

解决方法

您代码中的问题是 Action 没有将参数作为 ref,因此将在将 data 提供给 DllGet 方法之前创建它的副本。

//                    vvvvvvvvvvvvvvvvvvvvvvvvvvv 
CommonWrapper<UInt16>((UInt16 a) => DllGet(ref a),ref data);

您可以定义委托并在 lambda 中使用 Action,而不是 ref

所以你需要添加一个委托

private delegate void WrappedFunction<T>(ref T data);

并且需要在CommonWrapper

//                                    vvvvvvvvvvvvvvvvvvv
static private bool CommonWrapper<T1>(WrappedFunction<T1> dll_function_handle,ref T1 data)
{
    // Your code here
}

并且您需要将 ref 添加到 lambda

//                                                                      vvv
static public void WrappedGet(ref UInt16 data) { CommonWrapper<UInt16>((ref UInt16 a) => DllGet(ref a),ref data); }

所以整个代码是这样的:

private delegate void WrappedFunction<T>(ref T data);

// Reduce boilerplate by wrapping all calls to the DLL with this
static private bool CommonWrapper<T1>(WrappedFunction<T1> dll_function_handle,ref T1 data)
{
    // Commmon code for mutex handling etc
    // .... 
    
    // Call to function handle,sometimes data is in-parameter,other times out-param
    dll_function_handle(ref data);
    
    return true;
}

static private void DllSet(UInt32 data) { common_var = data; }
static public void WrappedSet(UInt32 data) { CommonWrapper<UInt32>((ref UInt32 a) => DllSet(a),ref data); }

static private void DllGet(ref UInt16 data){ data = 1234; }
static public void WrappedGet(ref UInt16 data) { CommonWrapper<UInt16>((ref UInt16 a) => DllGet(ref a),ref data); }
,

根据我的评论,这是与您的原始代码最相似的解决方案:

class TEST
{
    static UInt32 common_var = 0;

    // Reduce boilerplate by wrapping all calls to the DLL with this
    static private bool CommonWrapper<T1>(Action<T1> dll_function_handle,ref T1 data)
    {
        dll_function_handle(data);

        return true;
    }
    static private bool CommonWrapper<T1>(Func<T1,T1> dll_function_handle,ref T1 data)
    {
        data = dll_function_handle(data);

        return true;
    }

    static private void DllSet(UInt32 data) { common_var = data; }
    static public void WrappedSet(UInt32 data) { CommonWrapper<UInt32>((UInt32 a) => DllSet(a),ref data); }

    static private void DllGet(ref UInt16 data) { data = 1234; }
    static public void WrappedGet(ref UInt16 data) { CommonWrapper<UInt16>((UInt16 a) => { DllGet(ref a); return a; },ref data); }
}

就个人而言,如果丢弃任何输入值,我会避免使用 ref 参数。我会改为将参数声明为 out 或声明该方法的返回类型;这样,Func<T1,T1> 应该可以替换为更简单的 Func<T1>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。