I am trying to write the following code:
public const Size ImageSize = new Size() { Width = 28, Height = 28 };
But I get the error that Width and Height are read-only.
What is the recommended way to do this?
const is restricted to primitives that the compiler can directly write as IL directly. readonly should suffice here if Size is treated as immutable, i.e.
public static readonly Size ImageSize = new Size(28,28);
Note that if Size is a mutable struct, bad things can happen; I would recommend a property rather than a field to prevent a number of confusing side-effects.
The fundamental problem is that you cannot declare an object of type System.Drawing.Size as const. That indicates that the symbol is to be replaced at compile-time with the value of the constant.
Instead, you should use readonly. This is also a "constant" value in the sense that it cannot be modified once the constructor has run, but the objects are created at run-time instead of compile-time.
The following code compiles just fine:
public static readonly Size ImageSize = new Size() { Width = 28, Height = 28 };
public static readonly Size ImageSize = new Size(28,28);
You have to do this instead:
public readonly Size ImageSize = new Size(28, 28);
Making the instance read only to prevent it to be changed, as you cannot create Size as a constant.
From the docs:
A constant expression is an expression that can be fully evaluated at compile time. Therefore, the only possible values for constants of reference types are string and null.
The code you're writing:
public const Size ImageSize = new Size() { Width = 28, Height = 28 };
Actually compiles down to the same as this:
public const Size ImageSize = new Size();
ImageSize.Width = 28;
ImageSize.Height = 28;
The version your using, called the object initializer, is just syntactic shorthand for the latter version above. The two are logically identical. In the latter version you can see why it's giving you the error, you can't set properties on a const after it's been declared.
More to the point, I'm not sure if you can even use a reference type like that as a const. I'm not sure about that, as I can't say I ever tried it. You may try readonly instead. Though you may run into the same or similar issue.
Does Size have a constructor you can call with the parameters, rather than using the object initializer?
You can use :
public static readonly Size ImageSize = new Size(28, 28);
It's not actually a const, but it won't be changed after the initialization.
You need to use a constructor that takes width and height as parameters.
Also, the expression must be completely evaluable during compile time. That might not work with your Size type (don't know which one it is). If so (like with System.Drawing.Size), you might consider using readonly instead of const.
Related
I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
Whenever I have local variables in a method, ReSharper suggests to convert them to constants:
// instead of this:
var s = "some string";
var flags = BindingFlags.Public | BindingFlags.Instance;
// ReSharper suggest to use this:
const string s = "some string";
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
Given that these are really constant values (and not variables) I understand that ReSharper suggest to change them to const.
But apart from that, is there any other advantage when using const (e.g. better performance) which justifies using const BindingFlags instead of the handy and readable var keyword?
BTW: I just found a similar question here: Resharper always suggesting me to make const string instead of string, but I think it is more about fields of a class where my question is about local variable/consts.
The compiler will throw an error if you try to assign a value to a constant, thus possibly preventing you from accidentally changing it.
Also, usually there is a small performance benefit to using constants vs. variables. This has to do with the way they are compiled to the MSIL, per this MSDN magazine Q&A:
Now, wherever myInt is referenced in the code, instead of having to do a "ldloc.0" to get the value from the variable, the MSIL just loads the constant value which is hardcoded into the MSIL. As such, there's usually a small performance and memory advantage to using constants. However, in order to use them you must have the value of the variable at compile time, and any references to this constant at compile time, even if they're in a different assembly, will have this substitution made.
Constants are certainly a useful tool if you know the value at compile time. If you don't, but want to ensure that your variable is set only once, you can use the readonly keyword in C# (which maps to initonly in MSIL) to indicate that the value of the variable can only be set in the constructor; after that, it's an error to change it. This is often used when a field helps to determine the identity of a class, and is often set equal to a constructor parameter.
tl;dr for local variables with literal values, const makes no difference at all.
Your distinction of "inside methods" is very important. Let's look at it, then compare it with const fields.
Const local variables
The only benefit of a const local variable is that the value cannot be reassigned.
However const is limited to primitive types (int, double, ...) and string, which limits its applicability.
Digression: There are proposals for the C# compiler to allow a more general concept of 'readonly' locals (here) which would extend this benefit to other scenarios. They will probably not be thought of as const though, and would likely have a different keyword for such declarations (i.e. let or readonly var or something like that).
Consider these two methods:
private static string LocalVarString()
{
var s = "hello";
return s;
}
private static string LocalConstString()
{
const string s = "hello";
return s;
}
Built in Release mode we see the following (abridged) IL:
.method private hidebysig static string LocalVarString() cil managed
{
ldstr "hello"
ret
}
.method private hidebysig static string LocalConstString() cil managed
{
ldstr "hello"
ret
}
As you can see, they both produce the exact same IL. Whether the local s is const or not has no impact.
The same is true for primitive types. Here's an example using int:
private static int LocalVarInt()
{
var i = 1234;
return i;
}
private static int LocalConstInt()
{
const int i = 1234;
return i;
}
And again, the IL:
.method private hidebysig static int32 LocalVarInt() cil managed
{
ldc.i4 1234
ret
}
.method private hidebysig static int32 LocalConstInt() cil managed
{
ldc.i4 1234
ret
}
So again we see no difference. There cannot be a performance or memory difference here. The only difference is that the developer cannot re-assign the symbol.
Const fields
Comparing a const field with a variable field is different. A non-const field must be read at runtime. So you end up with IL like this:
// Load a const field
ldc.i4 1234
// Load a non-const field
ldsfld int32 MyProject.MyClass::_myInt
It's clear to see how this could result in a performance difference, assuming the JIT cannot inline a constant value itself.
Another important difference here is for public const fields that are shared across assemblies. If one assembly exposes a const field, and another uses it, then the actual value of that field is copied at compile time. This means that if the assembly containing the const field is updated but the using assembly is not re-compiled, then the old (and possibly incorrect) value will be used.
Const expressions
Consider these two declarations:
const int i = 1 + 2;
int i = 1 + 2;
For the const form, the addition must be computed at compile time, meaning the number 3 is kept in the IL.
For the non-const form, the compiler is free to emit the addition operation in the IL, though the JIT would almost certainly apply a basic constant folding optimisation so the generated machine code would be identical.
The C# 7.3 compiler emits the ldc.i4.3 opcode for both of the above expressions.
As per my understanding Const values do not exist at run time - i.e. in form of a variable stored in some memory location - they are embeded in MSIL code at compile time . And hence would have an impact on performance. More over run-time would not be required to perform any house keeping (conversion checks / garbage collection etc) on them as well, where as variables require these checks.
const is a compile time constant - that means all your code that is using the const variable is compiled to contain the constant expression the const variable contains - the emitted IL will contain that constant value itself.
This means the memory footprint is smaller for your method because the constant does not require any memory to be allocated at runtime.
Besides the small performance improvement, when you declare a constant you are explicitly enforcing two rules on yourself and other developers who will use your code
I have to initialize it with a value right now i can't to do it any place else.
I cannot change its value anywhere.
In code its all about readability and communication.
A const value is also 'shared' between all instances of an object. It could result in lower memory usage as well.
As an example:
public class NonStatic
{
int one = 1;
int two = 2;
int three = 3;
int four = 4;
int five = 5;
int six = 6;
int seven = 7;
int eight = 8;
int nine = 9;
int ten = 10;
}
public class Static
{
static int one = 1;
static int two = 2;
static int three = 3;
static int four = 4;
static int five = 5;
static int six = 6;
static int seven = 7;
static int eight = 8;
static int nine = 9;
static int ten = 10;
}
Memory consumption is tricky in .Net and I won't pretend to understand the finer details of it, but if you instantiate a list with a million 'Static' it is likely to use considerably less memory than if you do not.
static void Main(string[] args)
{
var maxSize = 1000000;
var items = new List<NonStatic>();
//var items = new List<Static>();
for (var i=0;i<maxSize;i++)
{
items.Add(new NonStatic());
//items.Add(new Static());
}
Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().WorkingSet64);
Console.Read();
}
When using 'NonStatic' the working set is 69,398,528 compared to only 32,423,936 when using static.
The const keyword tells the compiler that it can be fully evaluated at compile time. There is a performance & memory advantage to this, but it is small.
Constants in C# provide a named location in memory to store a data value. It means that the value of the variable will be known in compile time and will be stored in a single place.
When you declare it, it is kind of 'hardcoded' in the Microsoft Intermediate Language (MSIL).
Although a little, it can improve the performance of your code. If I'm declaring a variable, and I can make it a const, I always do it. Not only because it can improve performance, but also because that's the idea of constants. Otherwise, why do they exist?
Reflector can be really useful in situations like this one. Try declaring a variable and then make it a constant, and see what code is generated in IL. Then all you need to do is see the difference in the instructions, and see what those instructions mean.
I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
I'm working in a math library, and due to the inherent troubles of working with double I am coding all equality comparisons type a == b as Math.Abs(a - b) <= epsilon.
Also, by default, I want my formatted strings to be generated with the maximum considered precision. That is, if epsilon is 0.001 I want my default format to be N3.
Happily I did the following:
public static class Math3D
{
internal const int ROUND = 3;
public const double Epsilon = 1e-ROUND;
}
...and I got a compilation error. Apparently this is not allowed.
With this limitation I see no way I can define both interdependant constants as consts. Obviously I can define Epsilon as a readonly field but I feel doing so is somehow conceptually wrong. Am I missing an obvious way of how to do this?
If you're going to possibly be changing it, you should use readonly here. const should really be used for things that will never change, like π. The reason for this is because of a subtle difference between const and readonly.
The main issue is that if you change the value of the const, you must recompile all dependent clients that use the const, otherwise you can shoot yourself in the foot, badly. So for values that might change, don't use const, use readonly.
So, if the value is never going to change, just use const and then don't worry about defining Epsilon in terms of ROUND, just say:
internal const int ROUND = 3;
public const double Epsilon = 1e-3;
If you really want to make sure you don't accidentally change one without changing the other, you could add a small check in the constructor:
if (Epsilon != Math.Pow(10, -ROUND)) {
throw new YouForgotToChangeBothConstVariablesException();
}
You could even add conditional compilation so that only gets compiled in debug releases.
If it is going to change, use static readonly:
internal readonly int ROUND = 3;
public static readonly double Epsilon = Math.Pow(10, -ROUND);
With this limitation I see no way I can define both interdependant constants as consts. [...] Am I missing an obvious way of how to do this?
No, you need to do some kind of math using Math.Pow or Math.Log to go between ROUND and Epsilon and those are not acceptable for compile-time usage with const. You could write a miniature code generator to spit out these two lines of code based on a single input value, but I really question the value of investing time into that.
1e-ROUND, specifically 1e is not a valid literal integer. You would have to do something like,
public static readonly double Epsilon =
decimal.Parse(
string.Format("1E-{0}", ROUND),
System.Globalization.NumberStyles.Float);
Also, note the static readonly since you cannot use a const when the expression won't be known until runtime. The static readonly will work similarly to a const in this scenario.
If you prefer not dealing with strings, you can always do,
public static readonly double Epsilon = Math.Pow(10, -ROUND);
You could always just hard code the 3. Seeing as you are using constants, then have no intention of ever changing the value to anything other than 3 right? So you don't need to worry too much about DRY.
public static class Math3D
{
internal const int ROUND = 3;
public const double Epsilon = 1e-3;
}
If you are thinking you might want to change the 3, then const is not for you and your question becomes moot.
Edit:
This is not a direct answer to your question but have you considered changing Round and Epsilon into writable fields? If you use these for formatting / rounding, it's almost guaranteed they'll need to change on occasion - neither a const nor a readonly field will work for that.
public static class Math3D
{
internal static int s_Round;
internal static double s_Epsilon;
static Math3D ()
{
Round = 3;
}
public static double Epsilon
{
get
{
return ( s_Epsilon );
}
}
public static int Round
{
get
{
return ( s_Round );
}
set
{
// TODO validate
s_Round = value;
s_Epsilon = Math.Pow ( 10, -s_Round );
}
}
}
It's a clearly readable solution that won't break when you change things in the future.
I know this is probably just a terminology mismatch but if i'm not mistaken i believe c# is? unless i'm missing something obvious??
...
private const uint URL_COUNT = 18;
private string[] _urls;
public Redirector()
{
this._urls = new string[URL_COUNT];
...
}
...
Results in “A constant value is expected “ and underlines URL_COUNT in the array definition??
Whats URL_COUNT if it isn’t a const -ant value?!?!
EDIT
Phew, i thought for a second then i was going mad. I'm glad no one could repro this as that means it's just a local thing.
Thanks for your help guys.
This will only fail to compile when you supply both the dimension lengths and an array initializer. For example:
this._urls = new string[URL_COUNT];
will be fine, but:
this._urls = new string[URL_COUNT] { "One", "Two" };
will not. The latter requires a constant expression. Note that a const variable is not a constant expression, just a constant value. From the C# specification (3.0) par 12.6:
When an array creation expression
includes both explicit dimension
lengths and an array initializer, the
lengths must be constant expressions
and the number of elements at each
nesting level must match the
corresponding dimension length.
It is a constant and should work fine. The following code compiled fine for me with the C# 3 compiler:
using System;
class Foo
{
private const uint URL_COUNT = 18;
private string[] _urls;
public Foo()
{
this._urls = new string[URL_COUNT];
}
}
This works too, without any complaints from the compiler.
class Foo {
private const uint URL_COUNT = 18;
private readonly string[] _urls = new string[URL_COUNT];
}