Reputation: 35795
I have an optional parameter of type IEnumerable<int>
in my C# method. Can I initialize it with anything but null
, e.g. a fixed list of values?
Upvotes: 13
Views: 15337
Reputation: 6228
I have been using the accepted answer forever, but I just had a brainstorm, and I think it would be interesting to share.
Using the semantics of default()
with a struct
, you can do this:
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>))
{
}
The reason this works is because the default
of a struct is not null
, but is an instance of the struct as if it was called with the default constructor. Since default
is determined at compile time, the compiler is happy with it, and it just works.
Of course, you can change the contents of GetEnumerator
to return whatever you'd like, not just Enumerable.Empty
, this is just my use-case.
Disclaimer
I do not actually use this in my code, for fear of issues caused by boxing. I just wanted to post this as an interesting exploration of how C# works. Maybe there's a way to solve the boxing issue, if I think of one, I'll come back here and update.
Upvotes: 0
Reputation: 38200
Well since you need compile time constants you would have to set it to null
but then you can do the following in your method
list = list ?? new List<int>(){1,2,3,4};
Upvotes: 3
Reputation: 460078
No, you need a compile time constant.
But you could use an overload as work around:
public void Foo(int arg1)
{
Foo(arg1, new[] { 1, 2, 3 });
}
public void Foo(int arg1, IEnumerable<int> arg2)
{
// do something
}
Upvotes: 3
Reputation: 1380
How about making its default value as null, and within the method
numbers = numbers ?? Enumerable.Empty<int>();
or
numbers = numbers ?? new []{ 1, 2, 3}.AsEnumerable();
Upvotes: 4
Reputation: 23626
No. You can only have compile time constants. You can assign in to null and then
void SomeMethod(IEnumerable<int> list = null)
{
if(list == null)
list = new List<int>{1,2,3};
}
Next code snippet is take from well-known C# in Depth
book by Jon Skeet
. Page 371. He suggest to use null as kind of not set
indicator for parameters, that may have meaningful default values.
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);
}
}
Usage
AppendTimestamp("utf8.txt", "First message");
AppendTimestamp("ascii.txt", "ASCII", Encoding.ASCII);
AppendTimestamp("utf8.txt", "Message in the future", null, new DateTime(2030, 1, 1));
Upvotes: 16
Reputation: 109567
No - default parameters must be compile-time constants.
Your best bet is to overload the method. Alternatively, set the default value to null and inside your method detect a null and turn it into the list you want.
Upvotes: 4