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};
...
}
Related
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){
...
}
This question already has answers here:
C# Pass a property by reference
(8 answers)
Closed 8 years ago.
I have a process that I want to apply to multiple value-type properties of an arbitrary object, such that each property is modified in some way by the process. A method that applies the process to any given property passed to it would seem to be the way to go, but because the property is a value type it doesn't get changed unless I pass it by reference, but of course the C# compiler prevents properties being passed by reference.
How can I achieve the following without the compiler objecting or having to write messy multiple lines that just repeat the same conditional code for each property?
static internal void AssignStringValueOrLeaveIfNull(string newValue, string sampleValue)
{
if (!string.IsNullOrEmpty(newValue))
sampleValue = newValue;
}
...
AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
AssignStringValueOrLeaveIfNull(value2, anObject.SampleText2);
AssignStringValueOrLeaveIfNull(value3, anObject.SampleText3);
AssignStringValueOrLeaveIfNull(value4, anObject.SampleText4);
AssignStringValueOrLeaveIfNull(value5, anObject.SampleText5);
...etc, 30 times.
where anObject.SampleTextn are all strings.
I can't be the first person to have wanted to do something similar!
I'm using VS2008 (C#3.5)
TIA
You cannot. That concept does not exist. You would have to assign the value to a temporary local variable, use ref on the variable, and then assign it back to the property:
var tmp = anObject.SampleText1;
AssignStringValueOrLeaveIfNull(value1, ref tmp);
anObject.SampleText1 = tmp;
Or use a return value, which is probably simpler...
anObject.SampleText1 = AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
ref works with:
fields
local variables
array elements
parameters
It does not work with properties, since properties are actually method calls, and the result of a method call does not have a sensible location to ref it from. Note: at the IL level, you can have ref return values from methods, which would theoretically allow for something akin to this - but it is not exposed in C# at the moment (if ever), and it would not work with properties as they exist today.
You could write an ugly extension method that takes an expression representative of the property you want to set, and give it a chance to check whether your new values are null or empty (or different from the destination) before assigning the value.
public static void SetPropertyValue<T>(this T target, Expression<Func<T, string>> memberLamda, string value)
{
// Check if "new value" is null or empty and bail if so
if (string.IsNullOrEmpty(value))
return;
var memberSelectorExpression = memberLamda.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var property = memberSelectorExpression.Member as PropertyInfo;
if (property != null)
{
// Get the existing value and compare against the new value
// Only set the property if it's different from the existing value
if ((string)property.GetValue(target, null) != value)
{
property.SetValue(target, value, null);
}
}
}
}
Source
And then you could use it like:
anObject.SetPropertyValue(a => a.SampleText1, value1);
anObject.SetPropertyValue(a => a.SampleText2, value2);
This should allow you to avoid having the object marked as "dirty", but is rather expensive (as Marc mentioned in a comment on his answer).
This question already has answers here:
Is there a constraint that restricts my generic method to numeric types?
(24 answers)
Closed 8 years ago.
Is there a way to limit typing of T to be able to add default values to the function parameters?
public class Identity<T>
{
public readonly T Seed;
public readonly T Increment;
public Identity(T seed = 1, T increment = 1)
{
Seed = seed;
Increment = increment;
}
}
It is the T seed = 1 that i want to be able to do and maybe limit the T to non decimal numeric types like short, int, long...
You can only set "default" values that can be evaluated at compile-time and can be converted to all possible values of T. One example is using default:
public void Add(T parent = default(T))
{
....
}
Which doesn't work for your case, unless you want to treat "0" as a "magic" case and treat it as "1". But how would you implement it without restricting T to numeric values? (which you can't do with generics either)
The actual problem is that there's (probably) no way at all to specify a default value for a parameter of type T..
IF you can do it (I dont remember), than you could only specify:
T param1 = null // for T: class
T param1 = default(T) // for T: any
// T param1 = new T() // for T: new() -- cannot be possible, see Servy's comment
because there are no other "constructors" available for a generic type parameter T!
The compiler treats the T as an Object that has no operations and no constructors and no cast/conversions other than specified by the where clauses and/or the ones always inherited from object. Since you can specify only the above ops/requirements.. I think it cannot be done. Generics are not C++ templates ;)
When declaring an int..
int A = 10;
why not do the following instead?
int A = new Int()
A=10;
are both the same?
Because int is syntax sugar for Int32 which is a value type. Incidentally, so is the constant value 10 (an instance of the value type Int32). That's why you don't need to use new to create a new instance, but rather making a copy of 10 and calling it A. And similar syntax works with reference types as well, but with the difference that a copy isn't made; a reference is created.
Essentially, you can think of 10 as a previously declared instance of Int32. Then int A = 10 is just setting variable A to a copy of value 10 (if we were talking about reference types then A would be set to a reference to the instance instead of a copy).
To better illustrate here's another example:
struct SomeValueType {
public SomeValueType(){
}
}
public static readonly SomeValueType DEFAULT = new SomeValueType();
Then you can just do this:
SomeValueType myValueType = DEFAULT; // no neeed to use new!
Now imagine that SomeValueType is Int32 and DEFAULT is 10. There it is!
You may have seen Java, where int and Integer are two different things, and the latter requires you to write new Integer(10).
In C# int is a special alias for Int32, and for all intents and purposes they are the same. Indeed, to create a new instance of any type you'd have to write new Int32() or something.
However, because integers are primitive types in C# (and most programming languages), there is a special syntax for integer literals. Just writing 10 makes it an Int32 (or int).
In your example you are actually assigning a value to the a variable twice:
int a = new Int32(); // First assignment, a equals 0
a = 10; // Second assignment, a equals 10
You might imagine that since the second assignment overwrites the first, the first assignment is not required.
In C# there are two kinds of types, "reference types" and "value types". (Pointers are a third kind of type but let's not get into that.)
When you use the default constructor of a value type, all you are saying is "give me the default value of this value type". So new int() is neither more nor less than just saying 0.
So your program is the same as:
int i = 0;
i = 10;
if you write youe code like
int A = new Int();
the variable 'A' is assigned by the default value of int, so you can use variable 'A' without assigning a value to it(in c# we cant use a variable without assigning a value to it)
when using the keyword new it will automatically call the default constructor, it will assign default values to the variables.
int A = new Int();
It declares and initializes A to 0.
Basically, the new operator here is used to invoke the default constructor for value types. For the type int, the default value is 0.
It has the same effect as the following:
int A = 0;
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Cast int to Enum in C#
I fetch a int value from the database and want to cast the value to an enum variable. In 99.9% of the cases, the int will match one of the values in the enum declaration
public enum eOrderType {
Submitted = 1,
Ordered = 2,
InReview = 3,
Sold = 4,
...
}
eOrderType orderType = (eOrderType) FetchIntFromDb();
In the edge case, the value will not match (whether it's corruption of data or someone manually going in and messing with the data).
I could use a switch statement and catch the default and fix the situation, but it feels wrong. There has to be a more elegant solution.
Any ideas?
You can use the IsDefined method to check if a value is among the defined values:
bool defined = Enum.IsDefined(typeof(eOrderType), orderType);
You can do
int value = FetchIntFromDb();
bool ok = System.Enum.GetValues(typeof(eOrderType)).Cast<int>().Contains(value);
or rather I would cache the GetValues() results in a static variable and use it over and over gain.