C# 4.0: Method parameter default values as array - .net-4.0

Is it possible in C# 4.0 method default values parameters as array (for ex. string[] sArray)?
if yes, how to implement it?
I tried call function like below:
MethodA(string[] legends=new string[]{"a","b"},float[] values=new float[]{1,2}, string alt="sd");
It's not work

As others have said, default values can't be arrays. However, one way of avoiding this is to make the default value null and then initialize the array if necessary:
public void Foo(int[] x = null)
{
x = x ?? new int[] { 5, 10 };
}
Or if you're not going to mutate the array or expose it to the caller:
private static readonly int[] FooDefault = new int[] { 5, 10 };
public void Foo(int[] x = null)
{
x = x ?? FooDefault;
}
Note that this assumes null isn't a value that you'd want to use for any other reason. It's not a globally applicable idea, but it works well in some cases where you can't express the default value as a compile-time constant. You can use the same thing for things like Encoding.UTF8 as a default encoding.
If you want a value type parameter, you can just make that a nullable one. For example, suppose you wanted to default a parameter to the number of processors (which clearly isn't a compile-time constant) you could do:
public void RunInParallel(int? cores = null)
{
int realCores = cores ?? Environment.ProcessorCount;
}

Default values must be compile-time constant, which means arrays cannot be used.
The standard (pg 312) says this:
The expression in a default-argument must be one of the following:
a constant-expression
an expression of the form new S() where S is a value type
an expression of the form default(S) where S is a value type

Related

Why am I able to have null values in non-null variables?

Here is my kotlin class:
class Test{
val x: String = run {
y
}
val y: String = run {
x
}
}
The variables x and y both end up as null, despite being declared as non-nullable strings.
You can run it here. As you can see, you end up with null pointer exceptions from trying to call methods on x or y.
Why is this possible? How can you really have null safety with this in mind?
Well this is what your class decompiles to in Java:
public final class Test {
#NotNull
private final String x;
#NotNull
private final String y;
#NotNull
public final String getX() {
return this.x;
}
#NotNull
public final String getY() {
return this.y;
}
public Test() {
Test $this$run = (Test)this;
int var3 = false;
String var5 = $this$run.y;
this.x = var5;
$this$run = (Test)this;
var3 = false;
var5 = $this$run.x;
this.y = var5;
}
}
So your backing fields, x and y are declared first. They're not assigned a value yet so, in Java, that means their value is null because that's the default for an unassigned object reference.
After the getters, you have the constructor which is where the assignation is taking place. There are a few weird variables going around, but
Test $this$run = (Test)this;
is basically creating a variable that refers to this, the current object. And we can kinda reduce the assignment code down to
this.x = this.y // y is null, so x is set to null
this.y = this.x // x is null, so y is set to null
Because that default value for object references is null, whichever of your assignments runs first will always be reading a null value from the other variable (which, remember, you haven't explicitly assigned a value to yet).
Basically the order of initialisation matters in Kotlin, you can't refer to something that hasn't been declared yet. Like this won't work either:
class Thing {
val a = b
val b = "hi"
}
On the line where a is being assigned, the value of b is currently undefined. It won't run on the JVM either, because that code decompiles to basically this:
public final class Thing {
#NotNull
private final String a;
#NotNull
private final String b;
public Thing() {
this.a = this.b;
this.b = "hi";
}
}
and that this.a = this.b line will fail because "b may not have been initialised yet". You can get around that with the same trick in the decompiled version of your code, with the other variable assigned to this:
public Thing() {
Thing thing = (Thing) this;
this.a = thing.b;
this.b = "hi";
}
which will run, but a ends up assigned with the default value of null.
So basically, the code you're using is a tricky way to get around that kind of error and ultimately give you unexpected behaviour. Obviously your example is unrealistic (the results of a = b = a are inherently undefined), but it can happen with this kind of code too, where initialisation goes through other functions:
class Wow {
val a = doSomething()
val b = 1
fun doSomething() = b
}
In this case a ends up 0 on the JVM, the default value for an int, because when assigning a it basically goes on a detour through a function that reads b before that's been assigned its value. Kotlin (currently) doesn't seem to be capable of checking the validity of this kind of thing - so you'll run into problems trying to initialise things via functions sometimes:
class Wow {
// unassigned var
var a: Int
val b = 1
init {
// calls a function that assigns a value to a
doSomething()
}
fun doSomething() { a = 5 }
}
That will fail because it can't determine that a has been initialised, even though the init block does so, because it's happening as a side effect of another function. (And you could bury that assignment in any number of chained calls, which is probably why it's not a thing that's been "fixed" - if you start making guarantees about that kind of thing, it needs to be consistent!)
So basically, during initialisation you can do things which the compiler isn't able to catch, and that's how you can get around things like non-null guarantees. It doesn't come up often, but it's something to be aware of! And I'm only familiar with the JVM side, I'm assuming the undefined behaviour is platform-specific.
According to the Kotlin docs, "Data inconsistency with regard to initialization" can result in a NullPointerException.
Here are a couple links related to the topic:
https://kotlinlang.org/docs/null-safety.html#nullable-types-and-non-null-types
https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order
Edit: An example of a wrong answer! It's not circular: x is initialised to null because y is null at the time x is initialised (being uninitialised).
Well, it's circular. x is not null because y is not null which is not null because x is not null.
So it's not a valid program. Meaningful type inference can only be applied to valid programs.

Is the a way to use the default value of a non-nullable parameter when null is passed as an argument?

I looking for a way to have default values take the place of nulls when passed as arguments. My motivation is purely to reduce the amount of code written (I want to avoid having overloaded functions/constructors or manual 'if null' checks)
My use case is within a Spring RestController, I want default values of a method called by the controller to be used without needing to state those default values outside the function.
I thought perhaps that using named parameters might provide this functionality but my experiments show otherwise. Perhaps there is a way with the elvis operator?
Example Code:
fun someFunction(first: Long = 1, second: Int = 2 ) {
// Do something
}
#GetMapping
fun someEndpoint(#RequestParam("first") firstParam: Long?):ResponseEntity<Any> {
someFunction(firstParam) // Attempt 1: "Required: Long\n Found: Long?
someFunction(first = firstParam) // Attempt 2: Same error
}
Hopefully you can help
There aren't any specific language features that would do this for you, the default argument mechanism isn't connected to nullability in any way.
However, you can achieve this in a more manual fashion by making your parameters nullable, and immediately substituting default values inside the function if they're null:
fun someFunction(first: Long? = null, second: Int? = null) {
val actualFirst: Long = first ?: 1
val actualSecond: Int = second ?: 2
// Do something with actualFirst and actualSecond
}
The #RequestParam annotation has a default value option named "defaultValue".
you can use it like so:
#GetMapping
fun someEndpoint(#RequestParam(name = "first", defaultValue = "1") firstParam: Long):ResponseEntity<Any> {
someFunction(firstParam) // firstParam equals to 1 if null was passed to the endpoint
}

Casting dynamic to int succeeds but 'as int?' returns null

I am confused by some code results using dynamic.
I am parsing some JSON in C# using the Newtonsoft json.net libraries. The JSON string ends like this:
}],"Result":{"820":1,"821":1,"822":2,"823":0}}
and so I set up a class to contain the parsed JSON:
public class Poll
{
public Answer[] Answer { get; set; }
public dynamic Result { get; set; }
}
and then parse my JSON string with this line
var poll = JsonConvert.DeserializeObject<BallotsharePoll>(json);
and then this code to delve into the dynamic object:
if (poll.Result["820"] != null)
{
var votes = (int)(poll.Result["820"]).Value;
result[i] = votes;
}
This works. But my original code used int? and the line
var votes = (poll.Result["820"]).Value as int?;
which fails as shown in the watch window here:
This shows that
the dynamic value of poll.Result["820"] is {1},
the value of (int)(poll.Result["820"]).Value is 1,
but the value of (poll.Result["820"]).Value as int? is null
QUESTION: Why does as int? return null while casting to int results in 1?
I would rather use int? to cover the case where the dynamic value cannot be coerced into an int.
Consider this program:
using System;
static class Program {
static void Main() {
dynamic s = (short)1;
Console.WriteLine(s as int?);
Console.WriteLine((int)s);
}
}
The first WriteLine prints nothing, the second prints 1. Likely, the problem in your case is similar.
This is not intuitive behaviour, I'll happily admit. When using as with dynamic, what you get is pretty much s is int? ? (int?)s : null, and s is int? would return false with or without dynamic.
Sorry for exhuming a very old question but I know the answer behind this behavior.
To be short, the keyword "int?" is just a shortcut for the generic class Nullable, with the generic type T as Int.
So a dynamic, to be considered an int?, should be a Nullable instance.
if your Json was
}],"Result":{"820":{"Value":1,"HasValue":true},}}
the operation "as int?" would have worked.

How to change the value of a global variable in a function while there is a local variable of same name in C#

I want to change the global variable in a function where a local variable of same is already present.
int x=10; //global variable
void fun1()
{
fun2(5);
}
void fun2(int x)
{
x=7; //here i want that this statement assigns the value 7 to the global x
}
Just qualify it with this. It's a pretty common pattern, particularly for constructors:
public class Player
{
private readonly string name;
public Player(string name)
{
this.name = name;
}
}
While I view it as acceptable if your parameter really is meant to be a new value for the field (potentially in a method which creates a new instance based on the current one and the new value for the single field, for example), I would try to avoid it in general, just from a readability perspective. Of course, the names of your private fields are an implementation detail, but when reading the code for the method, it's confusing to have two different concepts represented by the same variable name.
Rename the local parameter value.
Like Yuriy Vikulov said.
this.x for non-static variables
int x=10; //global variable
void fun1()
{
fun2(5);
}
void fun2(int lx)
{
x=7; //if you want 7
x=lx; //if you want the paramValue
}
this.x for non-static classes
NameClass.x for static variables

Does PetaPoco handle enums?

I'm experimenting with PetaPoco to convert a table into POCOs.
In my table, I've got a column named TheEnum. The values in this column are strings that represent the following enum:
public enum MyEnum
{
Fred,
Wilma
}
PetaPoco chokes when it tries to convert the string "Fred" into a MyEnum value.
It does this in the GetConverter method, in the line:
Convert.ChangeType( src, dstType, null );
Here, src is "Fred" (a string), and dstType is typeof(MyEnum).
The exception is an InvalidCastException, saying Invalid cast from 'System.String' to 'MyEnum'
Am I missing something? Is there something I need to register first?
I've got around the problem by adding the following into the GetConverter method:
if (dstType.IsEnum && srcType == typeof(string))
{
converter = delegate( object src )
{
return Enum.Parse( dstType, (string)src ) ;
} ;
}
Obviously, I don't want to run this delegate on every row as it'll slow things down tremendously. I could register this enum and its values into a dictionary to speed things up, but it seems to me that something like this would likely already be in the product.
So, my question is, do I need to do anything special to register my enums with PetaPoco?
Update 23rd February 2012
I submitted a patch a while ago but it hasn't been pulled in yet. If you want to use it, look at the patch and merge into your own code, or get just the code from here.
I'm using 4.0.3 and PetaPoco automatically converts enums to integers and back. However, I wanted to convert my enums to strings and back. Taking advantage of Steve Dunn's EnumMapper and PetaPoco's IMapper, I came up with this. Thanks guys.
Note that it does not handle Nullable<TEnum> or null values in the DB. To use it, set PetaPoco.Database.Mapper = new MyMapper();
class MyMapper : PetaPoco.IMapper
{
static EnumMapper enumMapper = new EnumMapper();
public void GetTableInfo(Type t, PetaPoco.TableInfo ti)
{
// pass-through implementation
}
public bool MapPropertyToColumn(System.Reflection.PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
// pass-through implementation
return true;
}
public Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo pi, Type SourceType)
{
if (pi.PropertyType.IsEnum)
{
return dbObj =>
{
string dbString = dbObj.ToString();
return enumMapper.EnumFromString(pi.PropertyType, dbString);
};
}
return null;
}
public Func<object, object> GetToDbConverter(Type SourceType)
{
if (SourceType.IsEnum)
{
return enumVal =>
{
string enumString = enumMapper.StringFromEnum(enumVal);
return enumString;
};
}
return null;
}
}
You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.
Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.
If you are using PetaPoco's T4 generation and you want enums in your generated type, you can use the PropertyType override in Database.tt:
tables["App"]["Type"].PropertyType = "Full.Namespace.To.AppType";
I you want to store the value of the enum instead of the index number (1,2,4 for example) you can locate the update function in PetaPoco class because the code is "managed" etc, when you add it as nuget package it will store the .cs file to your project. If we would have the enum variable Color = {red, yellow, blue}
Instead of:
// Store the parameter in the command
AddParam(cmd, pc.GetValue(poco), pc.PropertyInfo);
change to:
//enum?
if (i.Value.PropertyInfo.PropertyType.IsEnum)
{
AddParam(cmd, i.Value.GetValue(poco).ToString(), i.Value.PropertyInfo);
}
else
{
// Store the parameter in the command
AddParam(cmd, i.Value.GetValue(poco), i.Value.PropertyInfo);
}
It would store "yellow" instead of 2