大家好,欢迎来到IT知识分享网。
小心使用 params object[]
Intro
最近发现可能会不小心遇到的 params
的一个 bug,记录一下,避免以后踩坑
Sample
示例代码如下:
private static void StringFormatTest()
{
InvokeHelper.OnInvokeException = ex =>
{
ConsoleHelper.InvokeWithConsoleColor(() => Console.WriteLine(ex), ConsoleColor.Red);
};
var format = "{0} 123 {1}";
InvokeHelper.TryInvoke(() =>
{
var str = string.Format(format, 1, 2);
Console.WriteLine(str);
});
InvokeHelper.TryInvoke(() =>
{
var str = string.Format(format, new[] { "1", "2" });
Console.WriteLine(str);
});
InvokeHelper.TryInvoke(() =>
{
var str = string.Format(format, new[] { 1, 2 });
Console.WriteLine(str);
});
// InvokeHelper.TryInvoke(() =>
// {
// var str = string.Format(format, new[] { 1, 2 }.Cast<object>().ToArray());
// Console.WriteLine(str);
// });
InvokeHelper.TryInvoke(() =>
{
var str = string.Format(format, new object[] { 1, 2 });
Console.WriteLine(str);
});
}
这几种写法分别能否正常输出,输出的结果是什么呢?
InvokeHelper.OnInvokeException = ex =>
{
ConsoleHelper.InvokeWithConsoleColor(() => Console.WriteLine(ex), ConsoleColor.Red);
};
这段指定了发生异常时,以红色字体输出异常信息
输出结果如下:
第三种方式报了异常,我们可以在 IDE 里看到方法对应的参数信息,如下:
可以看到实际调用的方法是一个参数的方法,我们看生成的对应的低版本的代码会是下面这样
Console.WriteLine(string.Format(this.format, new int[2]
{
1,
2
}.Cast<object>().ToArray<object>()));
这个两个参数的 int[2]
会被当成是一个 object
,也就是最终会是一个参数,而我们的 format 里需要两个参数,从而导致了报错
那为什么第二种方式不会报错呢,我们可以看下第二种方式对应的参数信息和低版本的代码会是什么样子:
Console.WriteLine(string.Format(this.format, (object[]) new string[2]
{
"1",
"2"
}));
这里的 string[]
直接转成了 object[]
这就是主要的差异,string[]
发生了数组协变,变成了 object[]
int
是值类型,不能发生协变为 object[]
,被隐式转换为了 object
第一种方式则是,每个 int
都换成为了 object
,变成了 string.Format(string format, object args0, object args1)
Console.WriteLine(string.Format(this.format, (object) 1, (object) 2));
Params object[]
有的小伙伴可能会认为是一个 string.Format
有单个或者多个的 object
参数 override 方法,我们也可以自己写一个只有 params
的方法来进行测试,示例如下:
private static void ParamsTest()
{
ParamsMethod(1, 2, 3);
ParamsMethod(new[] { 1, 2, 3 });
ParamsMethod(new[] { "1", "2", "3" });
ParamsMethod(new object[] { 1, 2, 3 });
}
private static void ParamsMethod(params object[] args)
{
Console.WriteLine(args.Length);
}
我们这个示例直接输出参数的数量,输出结果如下
可以看到和我们前面 string.Format
的结果是类似的,我们看下生成的低版本的 C# 代码是什么样的
ParamsSample.ParamsMethod(new object[3]
{
(object) 1,
(object) 2,
(object) 3
});
ParamsSample.ParamsMethod(new object[1]
{
(object) new int[3]{ 1, 2, 3 }
});
ParamsSample.ParamsMethod((object[]) new string[3]
{
"1",
"2",
"3"
});
ParamsSample.ParamsMethod(new object[3]
{
(object) 1,
(object) 2,
(object) 3
});
More
发生协变有的时候会很方便,但是有时候可能会导致一些问题,比如说下面这个示例:
object[] array = new [] { "Hello" , "World" };
array[1] = 123;
array
虽然声明的是 object[]
,但是实际上是一个 string[]
,在给它赋值一个 int
的成员时就会有类似下面的报错:
总而言之,在使用 params object[]
参数的时候需要小心一下自己传递的参数,避免发生一些运行时的错误
References
-
https://github.com/WeihanLi/SamplesInPractice/blob/master/BalabalaSample/ParamsSample.cs
-
https://www.jetbrains.com/help/resharper/CoVariantArrayConversion.html
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/145892.html