【问题标题】:Passing an explicit cast as a ref parameter (C#)将显式转​​换作为 ref 参数传递 (C#)
【发布时间】:2010-01-29 23:16:33
【问题描述】:

我有一个类,它主要是一个大数组的包装器和一些相关的内务管理。我有一个带有 ref 参数的函数。当我将类的实例传递给函数时,我希望发送数组。

我考虑过显式转换。假设我有一些具有 byte[] ref 参数的函数。

    public void SomeFunction(ref byte[] someBytes);

而且我有一些具有重载显式强制转换的类。

    class SomeClass
    {
        byte[] someBytes;
        public static explicit operator byte[](SomeClass someInstance)
        {
            return someInstance.someBytes;
        }
    }

现在我想以类为参数调用函数

    SomeClass someInstance = new SomeClass();
    SomeFunction(ref (byte[]) someInstance);

编译器抱怨“一个 ref 或 out 参数必须是一个可赋值的变量”。我不确定我只是没有正确地按摩编译器,还是你真的不能这样做。

我考虑过一个属性或函数的返回值,但你不能通过 ref 传递它们(在教育自己之后我明白了为什么......)

我不希望将数组设为公共字段,但这确实满足编译器的要求。 我假设我可以创建一个局部变量来引用数组,但这是在每个函数调用之前和之后的额外代码行...

编辑:可能值得注意的是 SomeFunction 是由第三方编写的,我无权更改它。更糟糕的是,我认为他们的参数实际上不需要参考...

【问题讨论】:

    标签: c# casting ref-parameters


    【解决方案1】:

    强制转换不是可赋值的变量;您正在从显式转换运算符传递返回值。

    您可以在将其作为 ref 传递之前创建一个保存正确转换值的变量:

    SomeClass someInstance = new SomeClass();
    byte[] someBytes = (byte[])someInstance;
    SomeFunction(ref someBytes);
    

    请注意,现在可以重新分配 someBytes 变量。如果您希望重新分配 someInstance 的内部值,则必须在调用 SomeFunction 后以某种方式重新分配 someInstance.someBytes

    【讨论】:

    • 所以事实证明,实际的解决方案要么是一个公共字段,要么是一个简短的方法,其唯一目的是掩盖一些要传入的局部变量的创建。我做了更多的挖掘和泛型也可能有帮助。
    • 对,一个简单的 setter 就足以更新 someInstance。作为替代方案,您可以创建一个 SomeFunction 将其作为参数并由 SomeInstance 实现的接口,并通过该接口实现您的逻辑。
    【解决方案2】:

    你不能这样做,你需要先将你的对象转换成一个变量的结果具体化。

    如果您要求的内容被允许,请考虑以下代码:

    public void SomeFunction(ref byte[] someBytes)
    {
        someBytes = new byte[] { 1, 2, 3 };
    }
    
    SomeClass someInstance = new SomeClass();
    SomeFunction(ref (byte[]) someInstance);
    // uh-oh, what is "someInstance" now?
    

    为什么参数标记为“ref”,您在这里要解决什么问题?

    【讨论】:

    • 该参数被标记为 ref 可能是因为最初的第三方开发人员正在将 C++ 库移植到 .NET。我要解决的问题是在没有使 someBytes 成为公共字段或创建局部变量的情况下围绕 ref 跳舞。我选择了“显式演员表”,因为我知道内务字段会丢失。我希望 someInstance 只会将 someBytes 的引用传递给 SomeFunction。与使用公共字段没有太大区别,但强制显式强制转换会使其不太容易被滥用。
    • 嗯,“ref”和“out”参数需要一个支持变量,实际上没有办法解决这个问题,所以你只需要定义你已经发现的变量。您当然可以在自己的类中制作 shim-methods 来为您进行翻译,然后调用这些方法,这反过来会进行强制转换,存储在变量中并调用实际方法,但这可能也不是一个好的解决方案。
    • 最终解决方案实际上涉及创建对 byte[] 的引用的本地副本并引用该本地副本。这在技术上违反了 ref 的观点,但我很确定第三方程序员认为 C# 中的 ref 与 C++ 中的 & 相同,这不是真的。
    【解决方案3】:

    在 C# 中可用作 ref 参数的值的范围受 CLR 允许的范围的限制。它在 CLI 规范第 12.4.1.5.2 和 12.1.6.1 节中指定,包括

    • 当前方法的参数
    • 局部变量
    • 对象的成员字段
    • 静态场
    • 数组元素

    演员表不适合其中任何一个,因此不能用作ref 值。在通过引用传递它之前,您需要将它分配给一个类似于 local 的值。

    【讨论】:

    • 感谢您对规范的引用!我有一段时间没有接触 C#,所以在某种程度上,这更像是一个学术问题,因为我充分探索了该语言的各种特性……而且肯定有很多。
    【解决方案4】:

    你真的必须强制转换 ref 参数吗?在我的情况下,这样的事情很好。

    byte[] someInstance = (byte[])new SomeClass(); 
    SomeFunction(ref someInstance);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 2018-01-20
      • 2011-11-19
      • 2019-03-11
      • 2011-01-31
      • 1970-01-01
      • 2013-01-17
      相关资源
      最近更新 更多