初始化IEnumerable< int>作为可选参数
本文关键字:参数 IEnumerable int 初始化 | 更新日期: 2023-09-27 17:51:08
在我的c#方法中有一个类型为IEnumerable<int>
的可选参数。我可以用null
以外的任何东西初始化它吗?例如,一个固定的值列表?
No。您只能使用编译时间常量。你可以将in赋值为null,然后
void SomeMethod(IEnumerable<int> list = null)
{
if(list == null)
list = new List<int>{1,2,3};
}
下一个代码片段摘自Jon Skeet
的著名C# in Depth
书。371页。他建议使用null作为参数的not set
指示器,这些参数可能具有有意义的默认值。
static void AppendTimestamp(string filename,
string message,
Encoding encoding = null,
DateTime? timestamp = null)
{
Encoding realEncoding = encoding ?? Encoding.UTF8;
DateTime realTimestamp = timestamp ?? DateTime.Now;
using (TextWriter writer = new StreamWriter(filename, true, realEncoding))
{
writer.WriteLine("{0:s}: {1}", realTimestamp, message);
}
}
使用AppendTimestamp("utf8.txt", "First message");
AppendTimestamp("ascii.txt", "ASCII", Encoding.ASCII);
AppendTimestamp("utf8.txt", "Message in the future", null, new DateTime(2030, 1, 1));
没有-默认参数必须是编译时常量。
最好的方法是重载该方法。或者,将默认值设置为null,并在方法中检测null并将其转换为您想要的列表。
如何将其默认值设置为null,并在
方法中numbers = numbers ?? Enumerable.Empty<int>();
或
numbers = numbers ?? new []{ 1, 2, 3}.AsEnumerable();
不,你需要一个编译时间常数。
但是你可以使用重载来解决:
public void Foo(int arg1)
{
Foo(arg1, new[] { 1, 2, 3 });
}
public void Foo(int arg1, IEnumerable<int> arg2)
{
// do something
}
既然你需要编译时间常量,你就必须将其设置为null
但是你可以在
方法中做以下操作 list = list ?? new List<int>(){1,2,3,4};
我一直在使用公认的答案,但是我刚刚有了一个头脑风暴,我想分享一下会很有趣。
使用default()
和struct
的语义,可以这样做:
public readonly struct EmptyEnumerable<T> : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator()
{
return Enumerable.Empty<T>().GetEnumerator();
}
public IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// ...elsewhere...
public void Foo<T>(IEnumerable<T> bar = default(EmptyEnumerable<T>))
{
}
之所以有效,是因为结构体的default
不是null
,而是该结构体的一个实例,就好像它是用默认构造函数调用的一样。由于default
是在编译时确定的,所以编译器对它很满意,并且它可以正常工作。
当然,您可以更改GetEnumerator
的内容以返回您想要的任何内容,而不仅仅是Enumerable.Empty
,这只是我的用例。
免责声明
我实际上没有在我的代码中使用它,因为担心装箱引起的问题。我只是想把这篇文章作为对c#工作原理的有趣探索。也许有办法解决装箱问题,如果我想到一个,我会回来更新。