Optional parameters - c#

I've got a method that takes a bunch of optional parameters and I'm overloading the method to supply the different combinations of signatures. Intellisense pops up with a bunch of different signatures but I think it looks quite confusing now because there are different combinations I need to provide, not just building up parameters on the end of the method signature.
Should I just not overload my method and stick to one signature so that the user of my method has to pass in nulls? It would make the signature clearer but makes the calling code look messier.

Are you restricted to using C# 1-3? C# 4 supports optional parameters and named arguments...
Until then, you should probably either stick with overloading or create a separate class with mutable properties, e.g.
FooOptions options = new FooOptions { Name="Jon", Location="Reading" };
Foo foo = new Foo(options);
That can all be done in one statement if you want... and if some of the properties are mandatory, then create a single constructor in FooOptions which takes all of them.
In C# 4 you'd be able to write:
Foo foo = new Foo(name: "Jon", location: "Reading");
if the constructor was written as
public Foo(string name,
int age = 0,
string location = null,
string profession = null)
Named arguments and optional parameters should make it a lot easier to construct immutable types with optional properties in C# 4 :)

Think about params argument of c# method.
void test(params object []arg) {
..
}

You could use the params keyword if the function definitions only vary in length (and not order, otherwise this wont be the best approach).Then in the function you can setup the values you need based on the parameter input

Related

C# reflection to check method body of assignment to fields

For the class below :
class A
{
private List<int> intList;
private List<bool> boolList;
public InitializeClass()
{
intList = new List<int>();
}
}
I want to use reflection to write a linter/post compiler of sorts, to check if a certain method really have any assignment to the class' fields or not. The purpose is to automatically check my own errors. The class cannot use constructor, so I need to call InitializeClass() manually.
I have MethodInfo method and all fields of class FieldInfo[] fields that I wanted to check already but have no idea how to go from here. From the example above, it should be able to detect that I haven't assign anything to boolList in the method body.
I ended up reading the code file directly using regular expression.
The file has some constraint, that is it can contains unlimited methods but each method cannot contain any brackets. (No if, etc.)
Then I use "({)(.*)(})" and choose the 2nd group to eliminate class's bracket, then from that I used "{(.*?)}" and iterate through matches for each method's body. (I don't care about method's name actually, I want to check the entire file) After that I read the method's content line by line and split things with characters like '=' or '.'

Named Parameters vs Optional Parameters

The optional parameters are nothing new in C# and I've known about that since the release of C# 5.0 but there is something I just came across. When I use Data Annotations for my MVC models such as the Required attribute I see this:
So I can do:
[Required(ErrorMessage="Something"]
However when I create my own methods with optional parameters like:
void Test(String x = null, String y = null) {}
I can pass arguments in both these ways:
Test(x = "Test") OR Test(x: "Test")
this while in the Required attribute I always have to use the = and if I use the : it will cause error.
for example:
Required(ErrorMessage:"Something") --> Compile time error
So what I see is that those Named Parameters are created differently than what I already knew about. And my question is How to make them for a method (How to create such Named Parameters like in the Required attribute).
An attribute has its own syntax. It uses the name=value form for named parameters.
For a normal method you can't use that form, you are stuck with the name:value form.
It would not be possible to use the name=value form for normal methods. The compiler would not be able to tell if you were trying to use a named parameter or if you were trying to assing a value to a variable and use the assignment as a parameter value.
Despite this syntax looking like a method call:
[Required(ErrorMessage="Something")]
An Attribute is a class, not a method. You aren't specifying an argument in the line above, you are initializing a property. See the example on the Attribute base class documentation to see what I mean.
The Attribute-specifying syntax is therefore similar to C#'s class initialization syntax:
new RequiredAttribute { ErrorMessage = "Something" };
There is currently no equivalent syntax in C# for specifying a named argument to a method.
If you do something like:
string y;
Test(y = "Test")
You can call a function with that syntax. But be careful... the y = "Test" is actually setting the variable y, and then passing that to the function! There is a side-effect there which is probably undesirable. Also "Test" is getting passed into parameter x of the Test function, not y because it's going in as the first parameter.
In short, you should always avoid using this syntax when calling a function, because it doesn't do what you're expecting.

C# generics: any way to refer to the generic parameter types as a collection?

I need to write a bunch of methods that take 1..N generic type parameters, eg:
int Foo<T1>();
int Foo<T1,T2>();
int Foo<T1,T2,T3>();
...
int Foo<T1,T2,T3...TN>();
Inside Foo() I would like to do something for each type, eg
int Foo<T1,T2,T3>() {
this.data = new byte[3]; // allocate 1 array slot per type
}
Is there any way to parameterize this so that I am not editing every variation of Foo(), something analogous to:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
}
Ideally, I'd also like to be able to get an array or collection of the types as well:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
// can do this
Type [] types = new Type[] { T1, T2, T3 };
// but would rather do this
Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS;
}
You can read the current generic parameters and their number from the MethodInfo.GetGenericArguments array.
You can retrieve the MethodInfo for your current method by using the MethodBase.GetCurrentMethod method.
Note that you will still need to supply several generic overloads of your method with different numbers of generic parameters, as C# and the CLI do not support variadic generic parameter lists.
So, your code sample for the method with three generic parameters could be written like this:
int Foo<T1,T2,T3>() {
MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
Type[] types = mInfo.GetGenericArguments();
this.data = new byte[types.Length];
}
1) You can get the number of template arguments via reflection: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx . This way, you can have common implementation for each Foo. In each Foo you can just call:
FooImpl();
The only difference (regarding the "GetCurrentMethod") is that you'll need to get method info of the previous method:
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
2) You could generate all Foo versions at runtime - all would share the same implementation of calling FooImpl only. Some details on generating methods at runtime: Creating a function dynamically at run-time and here: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx
The .NET framework regards a generic class or method with N type parameters as having a different name from one having more or fewer. It would probably be possible without a huge change to the framework to arrange things so that calling a function
foo<T>(autogeneric ref T it)
as:
foo(1, "George", 5.7);
would get translated as to:
struct foo99 {public int p1; public string p2; public double p3};
...
foo99 temp99;
temp99.p1 = 1;
temp99.p2 = "George";
temp99.p3 = 5.7;
foo1(ref temp);
That would allow a generic method to efficiently accept an arbitrary number of parameters. Being able to pass such anonymous structure by ref might not seem terribly useful, but it could be very powerful when combined with lambdas.
Normally, closing over local variables in a lambda expression would require hoisting the local variables to a heap object and building a delegate which targets that heap object. If one could use the above style, one could instead of creating a persistent closure object and a delegate and passing the delegate, simply hoist the appropriate variables to a structure and pass a byref to it along with a static delegate. This would only work in cases where the called routine wouldn't have to persist the passed-in closure, but on the flip side the caller would know that the called routine wouldn't be persisting the closure. Further, while no .NET languages would support such a thing and some framework changes might be required to allow code which did this to be volatile, passing by reference a structure some of whose members were also byrefs could make it possible for a lambda to access the enclosing procedure's ref parameters--something which is presently not possible (since there's no guarantee the created delegate wouldn't outlive the scope where it was created). Structures die when the scope they're in dies, so the problem wouldn't have to exist with them.
I wish .NET languages had a convenient way of expressing these concepts. The fact that closures can cause variables' lifetimes to be arbitrarily persisted means that code which has ever used a variable in a closure must assume that outside code could change it at any time. A struct-based approach wouldn't have that issue.
No.
You can not use the Type parameter as you want. But you could use something like Tuple. It allows you to Wrap generics. But you can not use the TypeParamter itself.

Why is a generic function member chosen over a non-generic one?

public enum EnumTest
{
EnumEntry
}
public class TestClass
{
public string FunctionMember(string s, EnumTest t = EnumTest.EnumEntry)
{
return "Normal";
}
public string FunctionMember<T>(T t)
{
return "Generic";
}
}
class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass();
Console.WriteLine(t.FunctionMember("a"));
}
}
This prints "Generic". Removing , EnumTest t = EnumTest.EnumEntry makes it print "Normal".
And yet the standard appears to be pretty clear, from 14.4.2.2 Better function member the first discriminator to be applied is:
If one of MP and MQ is non-generic, but the other is generic, then the non-generic is better.
Am I missing something or compiler bug?
You are missing something. And that is the following:
You call the method with one parameter. There is only one method that has one parameter, the generic one. So that's the one that's chosen.
Only if it didn't find a matching method it would look at other methods with optional parameters.
References:
C# 4.0 Specification, last paragraph in 21.4:
As a tie breaker rule, a function member for which all arguments where explicitly given is better than one for which default values were supplied in lieu of explicit arguments.
MSDN, heading "Overload resolution", last bullet point:
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
The C# Language Specification, Chapter "7.5.3.2 Better function member":
Parameter lists for each of the candidate function members are constructed in the following way:
The expanded form is used if the function member was applicable only in the expanded form.
Optional parameters with no corresponding arguments are removed from the parameter list
It continues like this:
Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN } [...]
At this point the method with the optional parameter is already out of the game. N is 1, but that method has two parameters.
The docs say:
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
In other words, the method without any optional arguments will be preferred.
With default values for method parameters the overload resolution got extended.
Conceptually the method overload resolution from pre v4 will be run. If that finds a match that match will be used. (Conceptually because this is not a description of how it works but how you can think of it)
In your case it finds exactly one match being your generic method
If it does not find a match it will look for methods that has a partial match and where the match can be completed with default values. In your case your none generice method would be found in this run however the resolution never comes this far due to already having found a match.
When removing the second paramter you end up in a situation where there's a generic and a non generic match. And the rule you qoute kicks in picking the non-generic.
All in all a good rule of thumb is that the most specific available method will be chosen.
A non-generic method that matches is more specific than a generic because the type can't vary.
A method with default parameters is less specific than one where the argument count matches the parameter count (the numbers are an exact match)
if two methods are available but one takes an argument of IFoo and the other takes a Foo (implemeting IFoo) then the latter will be chosen when passing a Foo object as argument because it's an exact match Ie. more specific

C# XNA Xbox, in this case optional parameters are not optional

Apparently optional parameters won't work in C# Xna when used on the Xbox, there non suportedness is stated during compilation.
I have a situation like this:
func(float? a = null, int? b = null)
With large numbers of thease optional parameters that default to the "undefined" value, null. This situation is required.
In the simplified example above this can be unwrapped, although this isn't as optional parameters allow:
func()
func(float? a)
func(int? b)
func(float? a, int? b)
However with large numbers of parameters this isn't practical.
Some combinations of parameters definedness isn't permitted and results in paths through the function where I throw argument exceptions, others result in various different things occurring depending on the values of the parameters. This is similar to polymorphism between functions with the same name but is not the same.
I could alternatively, and probbably most practically, require all the parameters instead.
func(float? a, int? b)
Then call as so:
func(null, 4)
Where the first is undefined.
Instead of using one of the above bodges, is there a way to enable optional parameters in C# XNA on Xbox?
I would use old-fashioned overloads that take different numbers of parameters, and forward the calls on from there, along with the "default" values. Zero code changes to the callers.
If the types are outside your control: extension methods to add the overloads.
I've certainly run on the XBOX with optional parameters, but it required some tweaking of the build settings. From what I recall it will not work with WP7 however.
I think it might have been related to the Language Version being used.
Check out the following links:
http://msdn.microsoft.com/en-us/library/ff827884.aspx
http://forums.create.msdn.com/forums/p/54007/327944.aspx
I don't think you can enable the optional parameters. Maybe you can use an alternative. like the params keyword that creates an array, you could just pass an object as parameter
public class MyParams
{
public float? a {get;set;}
public int? b {get;set;}
}
func(new MyParams { b = 5 });
With that solution, you have all the flexibility you might want. You can add, remove parameters without thinking of adding/removing new overload. And if you remove or edit a parameter, you'll get a compile time error, something you might not get with multiple overload.

Categories

Resources