Getting DefaultValue for optional Guid through reflection? - c#

I have the following code, that I use as sample for illustrating different scenarios:
public static void MethodWithOptionalGuid(Guid id = default(Guid)) { }
public static void MethodWithOptionalInteger(int id = 2) { }
public static void MethodWithOptionalString(string id = "33344aaa") { }
public static void MethodWithoutOptionalParameter(int id, Guid longId) { }
static void Main(string[] args)
{
var methods = typeof(Program).GetMethods(BindingFlags.Public | BindingFlags.Static).ToList();
foreach (var method in methods)
{
PrintMethodDetails(method);
}
Console.ReadLine();
}
static void PrintMethodDetails(MethodInfo method)
{
Console.WriteLine(method.Name);
foreach (var parameter in method.GetParameters().ToList())
{
Console.WriteLine(parameter.Name +
" of type " + parameter.ParameterType.ToString() +
" with default value:" + parameter.DefaultValue);
}
Console.WriteLine();
}
It prints the following:
MethodWithOptionalGuid
id of type System.Guid with default value:
MethodWithOptionalInteger
id of type System.Int32 with default value:2
MethodWithOptionalString
id of type System.String with default value:33344aaa
MethodWithoutOptionalParameter
id of type System.Int32 with default value:
longId of type System.Guid with default value:
The output seems fine for the last 3 methods.
My question is regarding the first one, MethodWithOptionalGuid: why the Guid's default value is not recognized?
I expected to receive something like "0000000-..." . I also tried initializing the optional parameter with new Guid() and same result. I tried as well other structs, like TimeSpan and the behavior is the same.
I expected that all value types would behave the same (as seen in integer example).
Extra: I found this thing while trying to use in Asp.Net MVC an action with an optional Guid parameter and failed (had to make the Guid nullable). Went through MVC code and found that it uses the DefaultValue at some point. So I made this code sample to better illustrate my issue.

The why is pretty relevant and something you really need to heed when you want to do something like this. Dragons live here. If you use ildasm.exe to look at the method then you'll see:
.param [1] = nullref
A null as a default for a structure type, uh-oh. The semantics for the .param directive is described in the CLI spec, Ecma-335, chapter II.15.4.1.4. It is very short, I'll copy-paste the entire chapter (edited for readability)
MethodBodyItem ::= .param ‘[’ Int32 ‘]’ [ ‘=’ FieldInit ]
This directive stores in the metadata a constant value associated with method parameter number Int32,
see §II.22.9. While the CLI requires that a value be supplied for the parameter, some tools can use the
presence of this attribute to indicate that the tool rather than the user is intended to supply the value of
the parameter. Unlike CIL instructions, .param uses index 0 to specify the return value of the method,
index 1 to specify the first parameter of the method, index 2 to specify the second parameter of the
method, and so on.
[Note: The CLI attaches no semantic whatsoever to these values—it is entirely up to compilers to
implement any semantic they wish (e.g., so-called default argument values). end note]
The [Note] is most relevant. When you use Reflection then you play the role of the compiler and it is up to you to interpret the default value correctly. In other words, you have to know that in C# the default value for a structure type is null.
This is otherwise a limitation in what can be stored in a [FieldInit]. The initialization value must be stored in the metadata of the assembly and is subject to the same kind of limitations of an [attribute] declaration. Just simple value types can be used, not structures. So by convention the C# designers worked around this by using null instead. Good enough for the C# compiler to understand that default(Guid) was intended.
That's not where the trouble ends, there are other ways to indicate an optional argument, the [OptionalAttribute] was used prior to C# v4.0. And is still used today, by COM interop libraries and other languages like VB.NET and C++/CLI. That's where the dragons live.
Ignoring those beasts for now, workaround code for what you have could look like this:
var def = parameter.DefaultValue;
if (parameter.ParameterType.IsValueType && def == null) {
def = Activator.CreateInstance(parameter.ParameterType);
}
Console.WriteLine(parameter.Name +
" of type " + parameter.ParameterType.ToString() +
" with default value:" + def);

Open your testfile with a decompiler of your choice and you will see that your code actually get compiled to:
public static void MethodWithOptionalGuid(Guid id = null) { }
This is why the DefaultValue property returns null.
When you use this parameter now, lets say you add:
Console.WriteLine(id);
The compiler will insert a
box [mscorlib]System.Guid
statement before the WriteLine. Now the output will be the expected "0000000-..."

Sorry - I can't tell you WHY it doesn't return the correct value but I've a workarround using this extension method:
public static object GetDefaultValue(this ParameterInfo p)
{
if (!p.Attributes.HasFlag(ParameterAttributes.HasDefault))
{
return null;
}
if (p.DefaultValue != null || p.RawDefaultValue != null)
{
return p.DefaultValue ?? p.RawDefaultValue;
}
return p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null;
}
Maybe it will help.

I guess the answer can be found in c# language specifications (someone may find something more relevant)
Point 4.1.2
When the operands of an expression are all simple type constants, it
is possible for the compiler to evaluate the expression at
compile-time. Such an expression is known as a constant-expression
(§7.19). Expressions involving operators defined by other struct types
are not considered to be constant expressions.
Through const declarations it is possible to declare constants of the
simple types (§10.4). It is not possible to have constants of other
struct types, but a similar effect is provided by static readonly
fields.
Even if we're not talking about expressions or consts here, it seems that only simple types (structs like int) can be evaluated /computed at compile time. That's why default(int) can be evaluated and then would display 0 in your code.
But other struct can't be computed at compile time, so I would say that it's the reason why they're evaluated to null.
When you set a default parameter value, it has to be a compile-time constant.
The tricky part is that you can put default(Guid) or new Guid() as an accepted compile-time constant (BUT evaluated to null), but... it can't be a const.
For example, you could not do
const Guid g = new Guid();

Related

Check if a type is managed inside a program [duplicate]

How do I check if a type T fits the unmanaged type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged? My first idea was typeof(T).IsUnmanaged or something similar, but that isn't a property/field of the Type class
According to unmanaged constraint documentations:
An unmanaged type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
Have the type sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, IntPtr or UIntPtr.
Be any enum type.
Be a pointer type.
Be a user defined struct that satisfies the unmanaged constraint.
Considerations
Usually calling MakeGenericType is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged constraint, you can use the following IsUnmanaged extension method'.
C# 7.3: It is supposed to be more reliable, but I should say, it's not. It seems for unmanaged constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
C# 8.0: Works as expected in C# 8.0
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged constraint. The following code has more rules rather than other answer to be able to handle cases like int? or (int,int):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
Docs - Unmanaged constraint
GitHub - C# 7.3 language design documents - Unmanaged type constraint
A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
GitHub - Proposal: Unmanaged constructed types #1504
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}

Aggregate: Seed with a null value [duplicate]

private static Matcher<T> EqualTo<T>(T item)
{
return new IsEqual<T>(item);
}
How do I modify the above method definition such that the following are valid/allowed.
EqualTo("abc");
EqualTo(4);
EqualTo(null); // doesn't compile. EqualTo<string>(null) does
Trying to port some Java code where null seems to be acceptable value for a T parameter.
Update
Thanks: for all the answers - especially Eamon and Jason. I didn't want the method calls to bother with type-inference. The following overload fixed it.
private static Matcher<object> EqualTo(object item)
{
return EqualTo<object>(item);
}
Actually the above question was a part of a larger puzzle. The end goal was for the following to work.
this.AssertThat(null, EqualTo(null));
this.AssertThat(null, Not(EqualTo("hi")));
this.AssertThat("hi", Not(EqualTo(null)));
Applied the same fix.. RFC. (Ignore the ugly extension method part - that's another problem. Wanted to have these methods in all test-fixtures without inheritance.)
public static void AssertThat<T>(this object testFixture, object actual, Matcher<T> matcher, string message = "")
{
AssertThat(anyObject, (T)actual, matcher, message);
}
public static void AssertThat<T, TSuper>(this object testFixture, T actual, Matcher<TSuper> matcher, string message = "") where T : TSuper
{
... check and assert
Consider the following method:
public bool IsNullString<T>(T item) {
return typeof(T) == typeof(string) && item == null;
}
Yes, this is a pathetically stupid method and using generics is pointless here, but you'll see the point in a moment.
Now consider
bool first = IsNullString<string>(null);
bool second = IsNullString<Foo>(null);
bool third = IsNullString(null);
In the first and second, the compiler can clearly distinguish the type of T (no inference is needed). In the third, how the compiler infer what T is? In particular, it can't distinguish between T == string and T == Foo, or any other type for that matter. Therefore, the compiler has to give you a compile-time error.
If you want to get around this, you either need to cast null
EqualTo((object)null);
or explicitly state the type
EqualTo<object>(null)
or define an overload
private static Matcher<object> EqualTo(object item) {
return new IsEqual<object>(item);
}
Not possible without explicitly specifying a T or doing a cast. Generics are compile time constructs and as such if the compiler can't figure out the type at compile time, then it won't compile (as you're seeing).
Since you can't do exactly what you are wanting to do, how about defining an EqualTo(object) overloaded method? That should allow your required syntax.
You may work around this limitation by using the following syntax:
EqualTo("abc");
EqualTo(4);
EqualTo(default(object));
//equivalently:
EqualTo((object)null);
default(T) is the value a field of type T has if not set. For reference types, it's null, for value types it's essentially memory filled with zero bytes (...which may mean different things for different types, but generally means some version of zero).
I try to avoid the null everywhere in my code nowadays. It hampers type inference elsewhere too, such as with the var declared field and in a ternary operator. For example, myArray==null ? default(int?) : myArray.Length is OK, but myArray==null ? null : myArray.Length won't compile.
Maybe implementing a non-generic EqualTo, which takes an Object as the argument type, would solve the issue of rewriting those code lines.

How does ToString on an anonymous type work?

I was messing with anonymous types, and I accidentally outputted it onto the console. It looked basically how I defined it.
Here's a short program that reproduces it:
using System;
class Program
{
public static void Main(string[] args)
{
int Integer = 2;
DateTime DateTime = DateTime.Now;
Console.WriteLine(new { Test = 0, Integer, s = DateTime });
Console.ReadKey(true);
}
}
Now, the output is:
{ Test = 0, Integer = 2, s = 28/05/2013 15:07:19 }
I tried using dotPeek to get into the assembly to find out why, but it was no help.[1] Here's the dotPeek'd code:
// Type: Program
// Assembly: MyProjectName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Assembly location: Not telling you! :P
using System;
internal class Program
{
public static void Main(string[] args)
{
Console.WriteLine((object) new
{
Test = 0,
Integer = 2,
s = DateTime.Now
});
Console.ReadKey(true);
}
}
So not much different, at all.
So how does it work? How does it output it like that?
Notes:
[1]: I forgot to turn on "Show compiler-generated code", that's the reason I didn't get how it works.
With anonymous objects...
The compiler generates an internal sealed class that models the
anonymous type. The anonymous type is immutable; all the properties
are read only. That class contains overrides of Equals() and
GetHashCode() that implement value semantics. In addition, the
compiler generates an override of ToString() that displays the value
of each of the public properties.
Source : link
Please, check #Ilya Ivanov answer to see some code about this subject.
Just to add some code to HuorSwords answer, compiler will generate ToString method for your example, as given below:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("{ Test = ");
stringBuilder.Append((object) this.<Test>__Field);
stringBuilder.Append(", Integer = ");
stringBuilder.Append((object) this.<Integer>__Field);
stringBuilder.Append(", s = ");
stringBuilder.Append((object) this.<s>__Field);
stringBuilder.Append(" }");
return ((object) stringBuilder).ToString();
}
It would be performance inefficient to use reflection here, when you have all required metadata at compile time.
Decompiled using dotPeek, this version may vary depending on used decompiler.
Note: as you also decompiled with dotPeek, try to look at Root Namespace. There you will find something similar to:
[DebuggerDisplay("\\{ Test = {Test}, Integer = {Integer}, s = {s} }", Type = "<Anonymous Type>")]
internal sealed class <>__AnonymousType0<<Test>
This is an example of what the compiled generates, when you define anonymous objects.
Anonymous types are still fully defined types ... simply: the compiler generates them entirely itself, and you never see the name / implementation (just: it matches the initializer you use in your code).
Actually, the ToString is not mentioned in regards to anonymous types in the specificaction (section 7.6.10.6); it is only required that Equals and GetHashCode work in terms of the properties. The example in the specification ("declares an anonymous type of the form") does not include a ToString override.
The MS compiler adds a property-based implementation of ToString as a courtesty - but also perhaps because the default ToString is the type name, which would by itself be meaningless (it is, after all, anonymous - the type name is pretty horrible to read, and includes generics syntax). Frankly it would be a good idea to only use this for debugging purposes.

Type of null literal in C#

I have a query about type of null.
I have a small program can anyone tell me about this.
public class TestApplication
{
public void ShowText(object ob)
{
Console.Write("Inside object");
}
public void ShowText(string str)
{
Console.Write("Inside string");
}
public void ShowText(int i)
{
Console.Write("Inside int.");
}
public void ShowText(char c)
{
Console.Write("Inside Character");
}
static void Main(string[] args)
{
new TestApplication().ShowText(null);
Console.Read();
}
}
Why it call the string function.
Is it means the type of null is string.
It might look a foolish conclusion but I am not able to find the region why it is calling the function of string.
Your question about the type of the null literal is answered here: What is the type of null literal?
But that doesn't really matter when talking about overload resolution. The actual null value itself will automatically be converted to whatever type it ends up as.
As for why the string overload is called:
You can't pass null as int and char parameters as they're value types, so those two overloads are out. (They could have been candidates had you made them nullable int? and char? types, but I won't go into that.)
Between the two other overloads taking reference types, string is a more specific type than object. That is, it derives from (and is therefore implicitly convertible to) object. Further, from the following section in the C# language spec (emphasis mine):
7.5.3.5 Better conversion target
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
...
Thus, the string overload is chosen as the best fit.
null can fit to any reference-type. and hence is a very good example for polymorphism.
lets say you have a Vehicle class. you create three more class Two-Wheeler, Three-Wheeler, Four-Wheeler.
if latter 3 class extends Vehicle class; it is called Vehicle is specified into those three categories.
So, given a value, say car, more specific fit to this value is Four-Wheeler.
Similar is the case with null. it can fit to either Object OR String; but more specific match is String.
Lets see how compiler thinks (specific to your code only) when it sees a call to ShowText(null) method
Find ShowText method.
Oh, I've found 4, methods, which one to call?!!
Lets see what argument is passed, hmm .. it's null.
Find ShowText method which has reference type as argument. all overloads with primitive arguments are ignored.
Oh No ... i can match it to eithe string OR object.
Which is more specific. i.e which comes first in inheritance hierarchy from below.
Hurray .. found it .. it's string .. lets call it.
And, for an exercise if you want to undestand that what will happen if compiler finds at step 6 mor than one matches ... define a ShowText(string[] vals) and see yourself.
This is an example of the overload resolution in C#, it does not prove that the type of the null is string.
null is a special value that is included in the domain of any reference type, it basically determines that there is not a valid reference. As such, it can be a string, an int?, an object etc, etc.
You can even cast null to any reference type, to get a "correctly" typed null, e.g. you must cast null if it's used as a value in a ? operator
int? value = (i > 0) ? i : null; // does not compile
int? value = (i > 0) ? i : (int?)null; //works

method overloading vs optional parameter in C# 4.0 [duplicate]

This question already has answers here:
Should you declare methods using overloads or optional parameters in C# 4.0?
(13 answers)
Closed 9 years ago.
which one is better? at a glance optional parameter seems better (less code, less XML documentation, etc), but why do most MSDN library classes use overloading instead of optional parameters?
Is there any special thing you have to take note when you choose to use optional parameter (or overloading)?
One good use case for 'Optional parameters' in conjunction with 'Named Parameters' in C# 4.0 is that it presents us with an elegant alternative to method overloading where you overload method based on the number of parameters.
For example say you want a method foo to be be called/used like so, foo(), foo(1), foo(1,2), foo(1,2, "hello"). With method overloading you would implement the solution like this,
///Base foo method
public void DoFoo(int a, long b, string c)
{
//Do something
}
/// Foo with 2 params only
public void DoFoo(int a, long b)
{
/// ....
DoFoo(a, b, "Hello");
}
public void DoFoo(int a)
{
///....
DoFoo(a, 23, "Hello");
}
.....
With optional parameters in C# 4.0 you would implement the use case like the following,
public void DoFoo(int a = 10, long b = 23, string c = "Hello")
Then you could use the method like so - Note the use of named parameter -
DoFoo(c:"Hello There, John Doe")
This call takes parameter a value as 10 and parameter b as 23.
Another variant of this call - notice you don't need to set the parameter values in the order as they appear in the method signature, the named parameter makes the value explicit.
DoFoo(c:"hello again", a:100)
Another benefit of using named parameter is that it greatly enhances readability and thus code maintenance of optional parameter methods.
Note how one method pretty much makes redundant having to define 3 or more methods in method overloading. This I have found is a good use case for using optional parameter in conjunction with named parameters.
Optional Parameters provide issues when you expose them publicly as API. A rename of a parameter can lead to issues. Changing the default value leads to issues (See e.g. here for some info: Caveats of C# 4.0 optional parameters)
Also, optional params can only be used for compile-time constants. Compare this:
public static void Foo(IEnumerable<string> items = new List<string>()) {}
// Default parameter value for 'items' must be a compile-time constant
to this
public static void Foo() { Foo(new List<string>());}
public static void Foo(IEnumerable<string> items) {}
//all good
Update
Here's some additional reading material when a constructor with default parameters does not play nicely with Reflection.
I believe they serve different purposes. Optional parameters are for when you can use a default value for a parameter, and the underlying code will be the same:
public CreditScore CheckCredit(
bool useHistoricalData = false,
bool useStrongHeuristics = true) {
// ...
}
Method overloads are for when you have mutually-exclusive (subsets of) parameters. That normally means that you need to preprocess some parameters, or that you have different code altogether for the different "versions" of your method (note that even in this case, some parameters can be shared, that's why I mentioned "subsets" above):
public void SendSurvey(IList<Customer> customers, int surveyKey) {
// will loop and call the other one
}
public void SendSurvey(Customer customer, int surveyKey) {
...
}
(I wrote about this some time ago here)
This one almost goes without saying, but:
Not all languages support optional parameters. If you want your libraries to be friendly to those languages, you have to use overloads.
Granted, this isn't even an issue for most shops. But you can bet it's why Microsoft doesn't use optional parameters in the Base Class Library.
Neither is definitively "better" than the other. They both have their place in writing good code. Optional parameters should be used if the parameters can have a default value. Method overloading should be used when the difference in signature goes beyond not defining parameters that could have default values (such as that the behavior differs depending on which parameters are passed, and which are left to the default).
// this is a good candidate for optional parameters
public void DoSomething(int requiredThing, int nextThing = 12, int lastThing = 0)
// this is not, because it should be one or the other, but not both
public void DoSomething(Stream streamData = null, string stringData = null)
// these are good candidates for overloading
public void DoSomething(Stream data)
public void DoSomething(string data)
// these are no longer good candidates for overloading
public void DoSomething(int firstThing)
{
DoSomething(firstThing, 12);
}
public void DoSomething(int firstThing, int nextThing)
{
DoSomething(firstThing, nextThing, 0);
}
public void DoSomething(int firstThing, int nextThing, int lastThing)
{
...
}
Optional parameters has to be last. So you can not add an extra parameter to that method unless its also optional. Ex:
void MyMethod(int value, int otherValue = 0);
If you want to add a new parameter to this method without overloading it has to be optional. Like this
void MyMethod(int value, int otherValue = 0, int newParam = 0);
If it can't be optional, then you have to use overloading and remove the optional value for 'otherValue'. Like this:
void MyMethod(int value, int otherValue = 0);
void MyMethod(int value, int otherValue, int newParam);
I assume that you want to keep the ordering of the parameters the same.
So using optional parameters reduces the number of methods you need to have in your class, but is limited in that they need to be last.
Update
When calling methods with optional parameters, you can used named parameters like this:
void MyMethod(int value, int otherValue = 0, int newValue = 0);
MyMethod(10, newValue: 10); // Here I omitted the otherValue parameter that defaults to 0
So optional parameters gives the caller more possibilities.
One last thing. If you use method overloading with one implementation, like this:
void MyMethod(int value, int otherValue)
{
// Do the work
}
void MyMethod(int value)
{
MyMethod(value, 0); // Do the defaulting by method overloading
}
Then when calling 'MyMethod' like this:
MyMethod(100);
Will result in 2 method calls. But if you use optional parameters there is only one implementation of 'MyMethod' and hence, only one method call.
What about a 3rd option: pass an instance of a class with properties corresponding to various "optional parameters".
This provides the same benefit as named and optional parameters, but I feel that this is often much clearer. It gives you an opportunity to logically group parameters if necessary (i.e. with composition) and encapsulate some basic validation as well.
Also, if you expect clients that consume your methods to do any kind of metaprogramming (such as building linq expressions involving your methods), I think that keeping the method signature simple has its advantages.
A good place to use optional parameter is WCF since it does not support method overloading.
This is not really an answer to the original question, but rather a comment on #NileshGule's answer, but:
a) I don't have enough reputation points to comment
b) Multiple lines of code is quite hard to read in comments
Nilesh Gule wrote:
One benefit of using optional parameters is that you need not have to do a conditional check in your methods like if a string was null or empty if one of the input parameter was a string. As there would be a default value assigned to the optional parameter, the defensive coding will be reduced to a great extent.
This is actually incorrect, you still have to check for nulls:
void DoSomething(string value = "") // Unfortunately string.Empty is not a compile-time constant and cannot be used as default value
{
if(value == null)
throw new ArgumentNullException();
}
DoSomething(); // OK, will use default value of ""
DoSomething(null); // Will throw
If you supply a null string reference, it will not be replaced by the default value. So you still need to check the input parameters for nulls.
To address your first question,
why do most MSDN library classes use
overloading instead of optional
parameters?
It is for backward compatibility.
When you open a C# 2, 3.0 or 3.5 project in VS2010, it is automatically upgraded.
Just imagine the inconvenience it would create if each of the overloads used in the project had to be converted to match the corresponding optional parameter declaration.
Besides, as the saying goes, "why fix what is not broken?". It is not necessary to replace overloads that already work with new implementations.
One benefit of using optional parameters is that you need not have to do a conditional check in your methods like if a string was null or empty if one of the input parameter was a string. As there would be a default value assigned to the optional parameter, the defensive coding will be reduced to a great extent.
Named parameters give the flexibility of passing parameter values in any order.

Categories

Resources