与函数参数有什么区别(params object [])

时间:2013-07-06 16:22:01

标签: c#

我正在尝试理解复杂的库(LinqToCodeDom),有很多lambdas和委托等等。两个相同的代码(在我看来)的工作方式不同。 在这两种情况下,我都尝试传递一个TypeA对象数组。

使用:

Func(new TypeA[] { new TypeA("value") });

不起作用:

TypeA [] v = new TypeA[] { new TypeA("value") }; 
Func(v);

Func接受params对象[]

当它不起作用时,它会在lib的深度某处与Null引用崩溃。

更新完整行。也许它比Func调用更复杂:

CodeMemberMethod cm = cls.AddMethod(
    MemberAttributes.Public, 
    m.ReturnType, 
    paramsAndName,
    Emit.@stmt(() =>
        CodeDom.Call(CodeDom.VarRef("obj"), m.Name)( *** PLACE FOR PARAM HERE*** )
);

3 个答案:

答案 0 :(得分:1)

修改

运行和调试之后我来到这里 - 不,我仍然不知道问题究竟是什么但是 - 它与表达式有关,这个调用在执行时生成两种不同类型的表达式

使用时

    Func(new TypeA[] { new TypeA("value") });

它会生成

    {() => Invoke(Call(VarRef("obj"), value(Demo.Program+<>c__DisplayClass1).m.Name),new [] {new TypeA("value")})}

当你使用

    TypeA [] v = new TypeA[] { new TypeA("value") }; 
    Func(v);

它会生成

   {() => Invoke(Call(VarRef("obj"), value(Demo.Program+<>c__DisplayClass1).m.Name),value(Demo.Program+<>c__DisplayClass1).v)}

注意差异

   new [] {new TypeA("value")}

VS

   value(Demo.Program+<>c__DisplayClass1).v

其中Demo是命名空间的名称,Program是类,v是你注意到的变量

编辑2.2

解释更多我制作这个示例应用程序

using System;

using System.Linq.Expressions;

namespace TestXml
{
    public class MyClass
    {
        public string Value { get; set; }
        public MyClass(string value)
        {
            Value = value;
        }

        public override string ToString()
        {
            return Value;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass[] parameter = new MyClass[] { new MyClass("1") };
            execute(() => TestInput( new MyClass[] { new MyClass("1") }));
            execute(() => TestInput(parameter));
        }

        public static void TestInput(params object[] parameters)
        {
            if (parameters != null && parameters.Length > 0) Console.WriteLine(parameters.GetType().FullName);
        }

        public static void execute(Expression<Action> exp)
        {
            Console.WriteLine(exp);
        }

        public delegate void ParamsDelegate(params object[] param);
    }
}

输出

() => TestInput(new [] {new MyClass("1")})
() => TestInput(value(TestXml.Program+<>c__DisplayClass0).parameter)

编辑3

要知道行为不同的原因我问the question on MSDN并得到了这个答案:

  

“execute(()=&gt; TestInput(new MyClass [] {new MyClass(”1“)}));”

     

不捕获任何内容,lambda表达式不使用任何内容   变量

     

“捕获指向参数变量的指针?”

     

我想你可以这么说。它不是一个指针,变量   参数存储在对象字段中,而不是存储在   堆栈,你看到的c__DisplayClass0是由一个生成的类   编译器保存参数变量

这导致说这主要是LinqToCodeDom如何评估表达式的错误,似乎他们没有处理这种情况。

答案 1 :(得分:1)

两种方法调用在功能上都是相同的。

在第一种情况下,C#编译器将生成一个变量来保存数组,这相当于第二种情况。

考虑以下C#代码(在LinqPad中):

void Main()
{
    CallFunc(new [] { new Foo() });

    var foos = new [] { new Foo() };
    CallFunc(foos);
}

public class Foo { }

void CallFunc(Foo[] foos) { }

生成的IL:

IL_0001:  ldarg.0     // These first two lines load 1
IL_0002:  ldc.i4.1    // for the size of the array
IL_0003:  newarr      Foo // Create the array of type Foo with the size
IL_0008:  stloc.1     // Pops the array into a variable
IL_0009:  ldloc.1     // These next two lines load
IL_000A:  ldc.i4.0    // the first index (0) of the array
IL_000B:  newobj      Foo..ctor // Creates a new Foo
IL_0010:  stelem.ref  // Loads Foo into the array
IL_0011:  ldloc.1     // Loads the array onto the stack
IL_0012:  call        CallFunc // Calls the function
IL_0017:  nop         // Same thing repeats below with some extra variable loading
IL_0018:  ldc.i4.1    
IL_0019:  newarr      Foo
IL_001E:  stloc.1     
IL_001F:  ldloc.1     
IL_0020:  ldc.i4.0    
IL_0021:  newobj      Foo..ctor
IL_0026:  stelem.ref  
IL_0027:  ldloc.1     
IL_0028:  stloc.0     // Pops the array into foos
IL_0029:  ldarg.0     
IL_002A:  ldloc.0     // Loads the array from foos
IL_002B:  call        CallFunc

CallFunc:
IL_0000:  nop         
IL_0001:  ret         

Foo..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ret         

代码之间的差异是两条加载和阅读foos的说明。

此IL的等效C#代码:

var arrayLength = 0;
var foos = new Foo[arrayLength];
var firstIndex = 0;
var foo = new Foo();
foos[firstIndex] = foo;
CallFunc(foos);

答案 2 :(得分:0)

两个代码示例之间以及刚刚调用

时没有区别
Func(new TypeA("value")); //the compiler will create an array for you because of params