C#: Default Value for Constructor with Array Argument [duplicate] - c#

This question already has answers here:
Setting the default value of a C# Optional Parameter
(3 answers)
Closed 9 years ago.
How does one define a function that takes an optional array with an empty array as default?
public void DoSomething(int index, ushort[] array = new ushort[] {},
bool thirdParam = true)
results in:
Default parameter value for 'array' must be a compile-time constant.

You can't create compile-time constants of object references.
The only valid compile-time constant you can use is null, so change your code to this:
public void DoSomething(int index, ushort[] array = null,
bool thirdParam = true)
And inside your method do this:
array = array ?? new ushort[0];
(from comments) From C# 8 onwards you can also use the shorter syntax:
array ??= new ushort[0];

If you can make the array the last argument you could also do this:
public void DoSomething(int index, bool wasThirdParam = true, params ushort[] array)
The compiler will automatically pass an empty array if it is not specified, and you get the added flexibility to either pass an array as a single argument or put the elements directly as variable length arguments to your method.

I know it's an old question, and whilst this answer doesn't directly solve how to get around the limitations imposed by the compiler, method overloading is an alternative:
public void DoSomething(int index, bool thirdParam = true){
DoSomething(index, new ushort[] {}, thirdParam);
}
public void DoSomething(int index, ushort[] array, bool thirdParam = true){
...
}

Related

C# passing int[] (array) with and without ref [duplicate]

This question already has answers here:
Why would ref be used for array parameters in C#?
(2 answers)
What is the use of "ref" for reference-type variables in C#?
(10 answers)
Closed 7 years ago.
I am slightly confused about this, as I have read that an int[] array, although int is a primitive type, since it's an array, it's a reference type variable.
What is the different then between a method such as:
public static void ChangeSomething(ref int[] array)
{
array[0] = 100;
}
and
public static void ChangeSomething(int[] array)
{
array[0] = 100;
}
When the array is modified, I can see the new value of 100 at index 0 for both of these calls.
Is there something different that happens under the covers which makes one better than another? Does the VS IDE allow both simply because perhaps the "ref" keyword clarifies the intention?
The difference is that you can assign the original variable directly in the method. If you change your method to the this:
public static void ChangeSomething(ref int[] array)
{
array = new int[2];
}
And call it like this:
var myArray = new int[10];
ChangeSomething(ref myArray);
Console.WriteLine(array.Length);
You will see that myArray only have a length of 2 after the call. Without the ref keyword you can only change the content of the array, since the array's reference is copied into the method.
If you modify the items of the array, there is no difference.
But if you redefined the array itself with larger array, there is the difference:
public static void ChangeSomething(ref int[] array)
{
array = new int[100]; //you are changing the variable of caller
}
and
public static void ChangeSomething(int[] array)
{
array = new int[100]; //you are changing local copy of array variable, the caller array remains same.
}

Using a reference value as parameter, with or without "ref"? [duplicate]

This question already has answers here:
Why use the 'ref' keyword when passing an object?
(10 answers)
Closed 7 years ago.
I came accross two Solutions(both work):
public List<Label> foo1(ref ISomeInterface[] all)
or
public List<Label> foo2(ISomeInterface[] all)
Is there a diffrerence, does it matter which of them I take ? Interface is a reference value and will give the parameter as reference anyway and "ref" will also get the reference...I think I can dismiss "ref" ... I wonder why the compiler does not give me an error...
Is there a diffrerence?
Yes, there is. Everything in C# is passed by value. When you pass a reference type by ref, you pass the actual reference pointer rather then a copy. That way, if you pass a reference type by ref and set it to a new reference via the new keyword, you'll alter the reference.
An example:
public static void Main(string[] args)
{
ISomeInterface[] somes = new[] { new SomeConcreteType() }
Foo(somes);
Console.WriteLine(somes.Length) // Will print 1
Foo(ref somes);
Console.WriteLine(somes.Length) // Will print 0
}
public List<Label> Foo(ref ISomeInterface[] all)
{
all = new ISomeInterface[0];
}
public List<Label> Foo(ISomeInterface[] all)
{
all = new ISomeInterface[0];
}
In first case you replace "global" (out of method) parameter all. In second case you will replace local copy of all parameter.
public List<Label> foo1(ref ISomeInterface[] all)
{
all = new ISomeInterface[0]; //you will get empty array outside method
}
public List<Label> foo1(ISomeInterface[] all)
{
all = new ISomeInterface[0]; //you will get empty array only inside method
}
It depends on what you want to do with the array.
If you want to modify the value in the foo1 method and use those modifications outside of the foo1 method, you may want to use the ref type version
If you just want to use the returned List<Label> you should use the option without ref.

Unable to pass List<char> to List<object> as a parameter? [duplicate]

This question already has answers here:
Why covariance and contravariance do not support value type
(4 answers)
Closed 7 years ago.
So I have a method in my code where one of the parameters is a IEnumerable<object>. For clarity purposes, that will be the only parameter for the example. I was originally calling it with a variable that was a List<string>, but then realized I only needed those to be chars and changed the signature of the variable to List<char>. Then I received an error in my program saying:
Cannot convert source type 'System.Collections.Generic.List<char>'
to target type 'System.Collections.Generic.IEnumerable<object>'.
In code:
// This is the example of my method
private void ConversionExample(IEnumerable<object> objs)
{
...
}
// here is another method that will call this method.
private void OtherMethod()
{
var strings = new List<string>();
// This call works fine
ConversionExample(strings);
var chars = new List<char>();
// This will blow up
ConverstionExample(chars);
}
The only reason that I could possibly think of as to why the first will work, but the second won't is because a List<char>() is convertible to a string? I don't really think that would be it, but that's the only long-shot guess that I can make about why this doesn't work.
Generic argument covariance doesn't support value types; it only works when the generic argument is a reference type.
You can either make ConversionExample generic and accept an IEnumerable<T> rather than an IEnumerable<object>, or use Cast<object> to convert the List<char> to an IEnumerable<object>.
This would be my solution:
// This is the example of my method
private void ConversionExample<T>(IEnumerable<T> objs)
{
...
}
// here is another method that will call this method.
private void OtherMethod()
{
var strings = new List<string>();
// This call works fine
ConversionExample<string>(strings);
var chars = new List<char>();
// This should work now
ConversionExample<char>(chars);
}

How can I reflect fixed width byte[] field information on a struct? [duplicate]

This question already has answers here:
C# Get type of fixed field in unsafe struct with reflection
(3 answers)
Closed 8 years ago.
I am trying to find a way to with reflected field information for fields on structs. My structs often contain fixed-width byte arrays. When I encounter one of these arrays while iterating over the list of struct fields, I need to catch if a field is an array and handle the array differently than my other field types. How can I do this?
As an example, here is a sample struct and the following method also articulates my problem?
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct MyStruct
{
public int IntegerVal;
public unsafe fixed byte MyByteBuff[20];
}
//Later in code...
public static void WorkWithStructs(Type t) //t will always be a struct
{
foreach (var f in t.GetFields())
{
if (f.FieldType == typeof(int)
{
//Do Int work
}
else if (???) //Test for a fixed-width byte array
{
// If MyStruct were passed to this method, this is where I
// would need to handle the MyByteBuff field. Specifically,
// I need to discern the object type (in this case a byte)
// as well as the length in bytes.
}
}
}
You can check for the presence of the FixedBufferAttribute custom attribute on your field types (found in the CustomAttributes collection of the type.
In your case, you be able to check for the presence of an attribute that matches the following:
[FixedBufferAttribute(typeof(Byte), 20)]
(adding the FixedBufferAttribute is done automatically - if you try to add it manually, you will get an error saying to use the fixed keyword instead).

set initialized arrays as parameters in C# [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
passing an empty array as default value of optional parameter in c#
This code is correct in C# 4.0
static void SomeMethod(int x, int y = 5, int z = 7)
{
}
SomeMethod(1);
but when applied on arrays it gives me errors
private static void diagonalFill(int[,] a,int[] fillType = {0,-1},int[] diagFill = {-1,1})
{
}
diagonalFill(array);
Could anyone show me the right way? 10x
Default parameter values are not possible with complex reference values. The first one works because the parameters are primitives that are stored on the stack and are copied by value. Arrays are complex reference values so they must first be allocated before they can appear as parameters.
Edit:
#Henk Holterman's comment is well taken. I don't have direct knowledge of whether the stack or heap come into play on this so this information is either mistaken or misleading. The primary criteria I am aware of is that only primitives types can be used. From this document,
A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType(), where ValType is a value
type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value
type.
The "primitives" list link above has been modified for 2010 to be called "built-in" types. It can be found here.
A default parameter value must be a compile time constant, so you can't do this.
You can't use initializers as default.
You could use:
private static void diagonalFill(int[,] a,
int[] fillType = null,
int[] diagFill = null)
{
if (fillType == null)
fillType = new int[] {0,-1};
if (diagFill == null)
diagFill = new int[] {-1,1};
...
}

Categories

Resources