【问题标题】:How to modify a boxed value type inside a method如何修改方法内的装箱值类型
【发布时间】:2008-11-12 10:15:28
【问题描述】:

我正在尝试构建一个库来简化 C# 中的后期绑定调用,但在使用参考参数时遇到了麻烦。我有以下方法来添加方法调用中使用的参数

    public IInvoker AddParameter(ref object value)
    {
        //List<object> _parameters = new List<object>();
        _parameters.Add(value);          

        //List<bool> _isRef = new List<bool>();
        _isRef.Add(true);

        return this;
    }

这不适用于值类型,因为它们被装箱为对象,因此它们不会被修改。例如:

int param1 = 2;
object paramObj = param1;
//MulFiveRef method multiplies the integer passed as a reference parameter by 5:
//void MulFiveRef(ref int value) { value *= 5; }
fi.Method("MulFiveRef").AddParameter(ref paramObj);

这行不通。后期绑定调用成功,保存参数(_parameters)的内部 List 确实被修改了,但调用外的值没有被修改。

有谁知道克服这个限制的简单方法? AddParameter 签名无法修改,与后期绑定调用一样,您无法提前知道参数的类型(以及在调用之前将调用的所有参数插入对象数组中的任何一种方式)

提前致谢。

【问题讨论】:

    标签: c# value-type late-binding


    【解决方案1】:

    如果值在方法内部发生变化,您需要声明一个临时 (object) 变量以将 (ref) 传递给该方法,然后自行拆箱:

        int i = 3;
        //...
        object obj = i;
        Foo(ref obj);
        i = (int)obj;
    

    请注意,这将不允许您在事件发生后更新值。事件或回调之类的东西可能是将更改传递回调用者的另一种方式。

    另请注意,C# 4.0 有一些技巧在 COM 调用的上下文中帮助解决此问题(其中ref object 如此常见[当然还有dynamic 用于后期绑定,如 Jon注])。

    【讨论】:

      【解决方案2】:

      你的方法并没有改变value——你为什么要通过引用传递它?这可能是有道理的,但对我来说并不是很清楚。请注意,您提供的示例代码无论如何都不会编译,因为ref 参数必须与参数的类型完全相同

      (另外,您是否知道 C# 4.0 和 .NET 4.0 将内置对后期绑定的支持?语言集成版本可能比仅库版本更易于使用。您确定吗?现在值得花时间在图书馆上吗?)

      编辑:您提供的代码确实无法编译。 ref 参数不会装箱,正是因为实参和参数类型必须完全相同。下面是一些示例代码来证明这一点:

      public class Test
      {
          static void Main()
          {
              int i;
              Foo(ref i); // Won't compile - error CS1502/1503
          }
      
          static void Foo(ref object x)
          {
          }
      }
      

      如果您当前的代码正在编译,那么它不是您在问题中提供的代码。也许您有另一个接受ref intAddParameter 重载?

      【讨论】:

      • 我很抱歉,你是对的。我最初发布的代码无法编译。
      【解决方案3】:

      好的,感谢 Jon Skeet 更正和 Mark Gravell 代码,我想出了这个界面:

              //This will be created with a factory
              IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
      
              int param1 = 2;
              object paramObj = param1;
      
              invoker.AddParameter(ref paramObj).Invoke("MulFiveRef");
      
              param1 = (int)invoker.Parameters[0];
      

      与我想象的不完全一样,但比我之前的界面更简单易读:

              IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
              int refValue = 10;
              object[] args = Args.Build(refValue);
      
              invoker.Call("MulFiveRef", Args.ByRefIndexs(0), args);
      
              refValue = (int)args[0];
      

      非常感谢大家的帮助:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-16
        • 1970-01-01
        • 1970-01-01
        • 2010-09-30
        • 2020-12-04
        • 1970-01-01
        • 2018-01-12
        相关资源
        最近更新 更多