Setting the default value of a C# Optional Parameter - c#

Whenever I attempt to set the default value of an optional parameter to something in a resource file, I get a compile-time error of
Default parameter value for 'message' must be a compile-time constant.
Is there any way that I can change how the resource files work to make this possible?
public void ValidationError(string fieldName,
string message = ValidationMessages.ContactNotFound)
In this, ValidationMessages is a resource file.

One option is to make the default value null and then populate that appropriately:
public void ValidationError(string fieldName, string message = null)
{
string realMessage = message ?? ValidationMessages.ContactNotFound;
...
}
Of course, this only works if you don't want to allow null as a genuine value.
Another potential option would be to have a pre-build step which created a file full of const strings based on the resources; you could then reference those consts. It would be fairly awkward though.

No, you will not be able to make the resource work directly in the default. What you need to do is set the default value to something like null and then do the resource lookup when the parameter has the default value in the body of the method.

Another option is to split your method into two, and have the one overload call the other, like so:
public void ValidationError(string fieldName)
{
ValidationError(fieldName, ValidationMessages.ContactNotFound);
}
public void ValidationError(string fieldName, string message)
{
...
}
This way also enables you to pass null as a value for message in case that is also a valid value for that parameter.

Related

Assigning default values to parameters when passed a NULL

Is there a better way of doing this -
if (Number.IsNotNullOrEmpty())
{
var status = _Logic.Order(data, Number);
}
else
{
var status = _Logic.Order(data);
}
Signature of the Order method -
Order(Data data, string number = "4a")
I am basically calling the same method in a different way based on if the number is NULL.
Since null is a valid value to be passed to a method, methods will typically have to deal with the possibility themselves that an argument may be null. Usually, you will see something like this then:
public void Example(string arg)
{
if (arg == null)
throw new ArgumentNullException(nameof(arg));
// …
}
That is for the case where passing a null value is not supported. But there is nothign wrong with explicitly allowing a null value to be passed and handling that internally. For example, instead of throwing an exception, you could simply assign a fallback value:
public void Example(string arg)
{
if (arg == null)
arg = "some default";
// …
}
If you cannot modify your method to add such a logic, then you will have to deal with this outside. If you do know the fallback value yourself, then you can simply use one of these many ways:
// null-coalescing operator
_logic.Order(data, number ?? "4a");
// ternary conditional operator
_logic.Order(data, number != null ? number : "4a" );
// adjust the value separately first
if (number == null)
number = "4a";
_logic.Order(data, number);
If you do not know the default value but instead have to rely on the default value that the method signature offers, or if you have to call a separate overload instead (where the second parameter is not used), then you will unfortunately have to use two separate calls for this. So you won’t be able to avoid this:
if (number != null)
_logic.Order(data, number);
else
_logic.Order(data);
Btw. of course, when dealing with strings, sometimes it makes more sense to use string.IsNullOrEmpty instead of a strict null check. I’ve kept this a strict null check to show the general idea. You can of course adjust it as necessary.
If you don't have control over the signature of Order, a simplified way to write your code from the caller's perspective would be to either use the ?? null-coalescing operator:
var status = _Logic.Order(data, Number ?? "4a");
But that only checks for null, so if you want to check for empty as well, you can do:
var status = _Logic.Order(data, string.IsNullOrEmpty(Number) ? "4a" : Number);
But if you do have control over the method, then rather than have an optional parameter (which can cause some problems down the line if modified), another option is to provide different overloads for the method:
public static void Order (Data data)
{
Order(data, "4a");
}
public static void Order (Data data, string number)
{
// Do stuff here
}
Of course this still doesn't prevent someone from passing null in the number field, so at some point you'll have to do some argument validation. This is pretty common in most methods:
public static void Order (Data data, string number)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (string.IsNullOrEmpty(number)) number = "4a";
// Do stuff here
}
You can use the following solution to assign default values to parameters when passed NULL:
public static void Order (Data data, string number=null)
{
// Do stuff here
}
Assuming you can't refactor the Logic class for some reason, but you need to use its default, you could maybe use this pattern:
_Logic.Order(data, Number.IsNotNullOrEmpty ? Number : DefaultForNumber.Value);
But the implementation for DefaultForNumber is kind of a pain.
static Lazy<string> DefaultForNumber = new Lazy<string>
(
() => typeof(Logic).GetMethod("Order").GetParameters()[1].DefaultValue as string
);

dynamically return an object based on string description of it's type

I have a database which stores user inputs in an abstract stringified form. These user inputs have a varchar column which describes its type (string, decimal, bool, dropdown etc).
Now this get's send to the front end to display some input elements in the browser. This works great!
However since the input is so generic the value is also a varchar. The problem I am facing is that I need to do some validation on the value. (e.g. some string input have a maxLength or regex specified, a decimal can have a min and max value).
so once I get back the value the user entered it is in string format and I want to parse it to the correct native type so I can start validating it.
I would like a function which returns the parsed value in it's correct type.
so I would have a function which is something like this:
public {something here} ParseValue(InputObject object, string type) {
// parse here based on type
// InputObject has a few properties like value, min, max, regex etc
// all as a string.
// for instance if type is datetime I want to return a new object
// which has parsed the value, min and max as datetime.
// it should also be possible for the type to be decimal and min, max
// and value should be decimal in the outputObject
}
I am coming from a dynamically typed background so I have no idea how to do something like this. or even if it is possible.
any help is appreciated!
You'd be best off if you don't directly try to evaluate the type by the Database-Datatype and instead store the "real" type in a seperate DB-Column. Except if you build an association between C#-Types and Database-Types because you can do something like this then:
String val = "123";
String type = "System.Int32";
Type tempType = Type.GetType(type);
if (tempType == null)
return null;
dynamic result = Convert.ChangeType(val, tempType);
Of course this would be applicable to the boundary values also. Note that Convert.ChangeType only works for very popular Types and is not universally useable and that it throws an Exception if theres something failing which need to be catched also.
What you could do is create an interface IValidatable that defines a method like Validate(). Then you could use that as a return type. Then you just parse your value using a switch (probably delegate this to some method or class) to an implementation of IValidatable. E.g.
public interface IValidatable {
bool Validate();
}
public class ValidateableInteger : IValidatable {
private int _value;
public ValidateableInteger(int i) {
_value = i;
}
bool Validate() {
//code where you validate your integer.
}
}
Note that this is not very flexible as you only have 1 method called validate, though clearly you can define multiple more generic methods that could implement different validations.
Moreover you can create more specific interfaces for e.g. numeric types (e.g. IValidateableNumeric and ValidateableInt : IValidateableNumeric)
Note that you're basically typing your input here though, which is kindof weird and unnecessary given the fact that you can just work with typed data to begin with.
In the end I would discourage people from bypassing type system this way. In this case especially there are plenty better ways of creating form elements while using typed data (checkout the Razor template engine).

Checking if multiple string parameter values are empty in a method

If I have a C# method similar to
public void MyMethod(object myObject, string s1, string s2, string s3, ...)
{ ... }
and I needed to do a value check on the strings (if !string.IsNullOrEmpty(var)), instead of going through each variable, because there are quite a few of if checks, is there a more generic way I could accomplish this?
I was hoping to use ParameterInfo until I found you could not retrieve the Value of the parameter. My parameters will either be "" or have a value of a number (as a string) or true/false (as a string) -- these are going into a web.config, hence the string. The name of the method variable is the parameter name going into the web.config. I'm preventing writing of parameters that have null/empty values into the web.config, hence the IsNullOrEmpty check.
Right now what I have for each method parameter is below, just to give you an idea of format.
string name, value;
if (!string.IsNullOrEmpty(s1))
{
name = "s1";
value = s1;
/* do stuff */
}
if (!string.IsNullOrEmpty(s2))
{
name = "s2";
value = s2;
/* do stuff */
}
/* too many of these */
I think that would be better to pass instead of string1, string2, etc.. something like an array of strings (string[]).
This way you will be able to pass 2 arguments, or 10000, and you will not need to check, because in your array you will not include nulls if you want ;)
EDIT: Dictionary wins
public void MyMethod(object myObject, Dictionary<int, string> yourParams)
{ ... }

How to tell if an out parameter was set already?

Is there a way to know if an out parameter was set already or not. This is the pseudocode for what I am looking for:
public virtual string blabla(long num, out bool bval)
{
if (!bval.HasValue)
{
//Do some default logic
bval = defaultValue;
}
return blabla2(num, bval);
}
You can't - you can't read the variable until it's been definitely assigned within your method. You should think of it as being like a local variable, declared but not assigned any value at the start of the method - but which you must assign a value to before you return. (It's okay not to have assigned a value to it if an exception is thrown.)
If you want a parameter which carries information as input to the method as well as propagating information out, you should use ref instead of out.
See my article on parameter passing for more information.
In addition to Jon's excellent answer, if you want the parameter to still be out, but need to see if it has been assigned a value at some place inside the method, you could use a local nullable type like follows:
public virtual string blabla(long num, out bool bval)
{
bool? bvalLocal;
... //I'm assuming there is some code here that may or
//may not assign bvalLocal?
// This whole if block may not be needed if the default
// value is the default for the type (i.e. false) as
// GetValueOrDefualt() will take care of that (see
// second to last line).
if (!bvalLocal.HasValue)
{
//Do some default logic
bvalLocal = defaultValue;
}
bval = bvalLocal.GetValueOrDefault();
return blabla2(num, bval);
}

Handling Reference Types

When reference variable can be passed by reference :
class Example
{
public string str="Demo";
public int[] intValues={1,3,4,5};
public static void StrPassing(string someStr)
{
string otherStr="Changed!";
someStr=otherStr;
}
public static void NumPassing(int[] a)
{
a[2] = 115;
}
}
static void Main(string[] args)
{
Example ex = new Example();
Example.StrPassing(ex.str);
Example.NumPassing(ex.intValues);
foreach (int i in ex.intValues)
{
Console.WriteLine(i);
}
Console.WriteLine(ex.str);
Console.ReadLine();
}
the value of intValues[2] is changed as 115 as the reference is being passed.But the value of the string "str" (demo) is not changed to "Changed!".What is the reason for it?.can i take it as Arrays are passed by reference and other reference types are passed by
value?
Whatever you pass to a method as arguments is passed by value which, for reference types, means that a reference is passed by value. So you can't change the object to another one but you can surely change its contents (because that doesn't change the actual reference, just some memory elsewhere).
As your example with the array demonstrates you take the array reference (but don't change it) and change a value in the array. This is just like taking some object and changing a property value. You can do this just fine from within a method too.
If you want to change a string, which is an immutable object in .NET, then you need to resort to ref parameters:
public static void StrPassing(ref string someStr)
{
string otherStr="Changed!";
someStr=otherStr;
}
And call it like this:
string foo = "foo";
StrPassing(ref foo);
Console.WriteLine(foo); // should print "Changed!"
The ref keyword ensures that your method gets the actual reference to the string and can change it, instead of just a copy of the reference. So then you can replace the object by an entirely new one.
To come back to your array: You'd have a hard time too, to change the passed array to an entirely different array:
public static void NumPassing(int[] a)
{
a = new int[15];
}
wouldn't work too because then you'd try exactly the same as changing a string to an entirely different string.
You need to distinguish between changing which object a variable refers to and changing *the content of the object".
In this code:
public static void StrPassing(string someStr)
{
string otherStr="Changed!";
someStr=otherStr;
}
... you are changing the value of someStr. You're not making any change to the string that someStr originally refers to. Indeed, you can't because strings are immutable. (If it were a StringBuilder, you could set the length to 0 and then append "Changed!")
Changing the value of someStr has no effect because the argument (ex.str) was passed by value. (The value in question is a reference, but that doesn't mean it's passed by reference.)
Now compare that with this code:
public static void NumPassing(int[] a)
{
a[2] = 115;
}
Here you're not changing the value of a - you're changing the contents of the array that a refers to.
In short, unless you use ref/out, arguments will be passed by value - but for reference types that value is just a reference.
I have an article on parameter passing which goes into all of this in a lot more detail.
What you'd need to do is change the signature for StrPassing to look like this:
public static void StrPassing(ref string someStr)
Strings are special in C#. They are immutable reference types which makes they exhibit similar behavior as value types.
Here's a good discussion.

Categories