简体   繁体   English

C# 不能使用 params object[] 而不是 __arglist

[英]C# cannot use params object[] instead of __arglist

I am trying to call an unmanaged dll. While looking for information about this and trying it, I thought I could use params object[] instead of __arglist, so I changed it like the following code, but got different results.我正在尝试调用一个非托管 dll。在查找有关此信息并进行尝试时,我认为我可以使用 params object[] 而不是 __arglist,因此我将其更改为以下代码,但得到了不同的结果。 Why does this work differently?为什么这会有所不同?

using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    internal class Program
    {
        [DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        internal static extern int printf(string format, __arglist);
        
        [DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        internal static extern int printf(string format, params object[] i);

        static void Main(string[] args)
        {
            printf("Print Integer: %d\n", __arglist(10));  // Print Integer: 10
            printf("Print Integer: %d\n", 10);             // Print Integer: 1363904384
        }
    }
}

Because they're not the same thing.因为它们不是一回事。 __arglist is specifically and only for var args in unmanaged code. __arglist专门用于非托管代码中的 var args。 The params keyword is something else entirely and the generated code just builds an array for you from the list of parameters. params 关键字完全是另一回事,生成的代码只是从参数列表中为您构建一个数组。 All it is doing is allowing you to write MyFunc(p1,p2,p3) instead of MyFunc(new object [] { p1, p2, p3}) .它所做的只是允许您编写MyFunc(p1,p2,p3)而不是MyFunc(new object [] { p1, p2, p3}) On your second example, that number is probably the address of the parameter array passed to printf.在您的第二个示例中,该数字可能是传递给 printf 的参数数组的地址。

This is a brief explanation on how params and __arglist work:这是关于params__arglist如何工作的简要说明:
When you write当你写

void MyFunction(int a, double b, params string[] c)
{
    some code
}

You actually just do the following:您实际上只需执行以下操作:

void MyFunction(int a, double b, [ParamArrayAttribute] string[] c)
{
    some code
}

The ParamArrayAttribute just instructs the compiler to allow calls of the form: ParamArrayAttribute 只是指示编译器允许调用以下形式:

MyFunction(3, 1.2, "foo", "bar", "baz");

That happens in addition to the "correct" way to call the method除了调用方法的“正确”方式之外,还会发生这种情况

MyFunction(3, 1.2, new string[] {"foo", "bar", "baz"});

The compiler simply convert the first call to the second one, it is just syntactic sugar and nothing more.编译器简单地将第一个调用转换为第二个调用,它只是语法糖,仅此而已。 The method MyFunction has 3 parameters: MyFunction 方法有 3 个参数:

  • int a诠释
  • double b双b
  • string[] c字符串[] c

On the other hand, printf does not take 2 arguments, one of type string and one of type object[], printf actually does not even know what a .net string , object or object[] even is.另一方面, printf采用 2 个 arguments,一个是字符串类型,一个是对象 [], printf实际上甚至不知道 .net stringobjectobject[]是什么。 printf is defined as: (in C) printf定义为:(在 C 中)

int __cdecl printf(const char *Format, ...);

printf takes one argument of Type char * (the .net interop automatically converts the .net string object to the unmanaged char * type), and then it can optionally take any number of additional arguments of any (unmanaged) type. printf采用一个char *类型的参数(.net 互操作自动将 .net string object 转换为非托管char *类型),然后它可以选择采用任意数量的任何(非托管)类型的附加 arguments。 Here is the crucial part, this happens by pushing the additional parameters in the stack and not by pushing an array pointer with the additional parameters, which is what the inperop thinks due to your deceleration.这是关键部分,这是通过将附加参数压入堆栈而不是通过将数组指针压入附加参数来实现的,这是 inperop 认为由于您的减速而发生的。 c# does not support this functionality... well... exept if you consider the "unsupported __arglist keyword", as per Microsoft sayings (check out Compiler Error CS1952 to laugh at their correction suggestion). c# 不支持此功能......好吧......如果你考虑“不受支持的__arglist关键字”,按照微软的说法(查看编译器错误 CS1952以嘲笑他们的更正建议)。 So, c# actually supports varargs afterall.所以,c# 毕竟实际上支持可变参数。

Now, the 1363904384 is just the pointer to an array containing the value 10, the .net inperop thinks it should pass an array as an argument (in the stack) while printf wants to have the value as an argument (in the stack).现在,1363904384 只是指向包含值 10 的数组的指针,.net inperop 认为它应该将数组作为参数传递(在堆栈中),而 printf 想要将值作为参数(在堆栈中)。

PS: The Interop marshals the object[] as an int[] for your particular case, if you try to pass an object (besides string ) you will get an exception. PS:如果您尝试传递 object(除string之外),Interop 会将object[]编组为int[] ,您将得到一个异常。 Object arrays do not make much sense outside the scope of .net, objects in general do not make sense (thought, arrays do make sense). Object arrays 在 scope 之外的 .net 没有多大意义,对象一般没有意义(以为,arrays 确实有意义)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#变长args,这更好,为什么:__ arglist,params数组或字典 <T,K> ? - C# variable length args, which is better and why: __arglist, params array or Dictionary<T,K>? 如何在C#控制台参数中使用单引号而不是双引号? - How to use single quotes instead of doublequotes for C# console params? 如何将我的__arglist参数发送到C#中的另一个函数? - How to send my __arglist parametr to another function in C#? C#params object []奇怪的行为 - C# params object[] strange behavior 如何在C#中使用定义的对象而不是字符串? - How to Use defined Object instead of a string in C#? 字段&#39;params&#39;与C#中的expando对象 - field 'params' with an expando object in C# 在 C# 中使用十进制值作为属性参数? - use decimal values as attribute params in c#? 使用object []和object [] []作为参数的C#调用方法(params object [] []) - C# call method (params object[][]) with object[] and object[][] as parameters 无法将没有输入参数的void类型隐式转换为字符串c# - Cannot implicitly convert type void with no input params to string c# 成员 'object.equals(object?, object?' 不能通过实例引用访问;在列表删除 c#? - Member 'object.equals(object?, object?' cannot be accessed with an instance reference; quality it with a name instead on string in list removal c#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM