59

I have a class divided in two partial files, like this:

public partial class PersonRepository : BaseRepository<Person>
{
    public static readonly string ColumnID = "ID";
    ...

and

public partial class PersonRepository : BaseRepository<Person>
{
    public List<Person> GetByCompany(int companyID, string sortExpression = ColumnID)
    {
    ...

But the compiler keeps saying that sortExpression "must be a compile-time constant". To me it seems a perfect compile-time constant, so I don't understand where the problem is.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Alessandro
  • 3,666
  • 2
  • 28
  • 41

8 Answers8

60

No, the expression PersonRespository.ColumnID is not classified as a compile-time constant. The expression "ID" is, but that's not what you're using as the default parameter.

In particular, if ColumnID is "just a normal field" then any references to it will be resolved as a field - so if you compile an assembly which refers to the field, then change the value and rebuild the assembly containing PersonRepository, the referring assembly will see that change.

If you change your declaration to:

 public const string ColumnID = "ID";

then it is a compile-time constant expression. That means in our previous scenario, the value of the constant is baked into any code that refers to it - and changing the value later without recompiling that referring code won't change the value used by that referring code.

See section 7.19 of the C# 4 language specification for more details about what counts as a constant expression.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you! Can you explain me why my expression is not a compile-time constant? – Alessandro Oct 06 '11 at 08:47
  • 2
    @Alessandro: All `const` members are implicitly static. – Jon Skeet Oct 06 '11 at 08:53
  • Ok, but If I have `readonly ColumnID` in the same assembly as `GetByCompany` than how is it different from `const ColumID`? I still need to recompile referenced assembly to get the change, right? Also, I can always write `...string sortExpression = null) { sortExpression = sortExpression ?? ColumnID;...` The idea of variable default parameter seem to be nice future. Is it considered, a bad practice or is it disallowed just because some technical nuances? – Paweł Audionysos Nov 27 '18 at 19:40
  • @PawełAudionysos: It's different because the value can't be baked into each use of it, which is true for a `const` expression. – Jon Skeet Nov 27 '18 at 19:46
  • @PawełAudionysos: Using null as a default value that's then replaced by a potentially non-constant value is a reasonable pattern, yes. But Stack Overflow comments aren't intended to be used for questions like this. – Jon Skeet Nov 27 '18 at 20:23
7

You must declare your ColumnID as const.

The static readonly string will be instantiated when the class is first accessed in your code, and you could also initialize it with the return value of a static method, so it's not a compile-time constant for the compiler (even if in this case it obviously is for a person reading the code).

Paolo Tedesco
  • 55,237
  • 33
  • 144
  • 193
5

const is something declared with const keyword.

readonly field can be assigned in constructor and its not compile time constant. the code that you've written right now runs in initializer (before constructor). const fields are 'baked' in as constants.

Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131
5

change

public static readonly string ColumnID = "ID";

to

public const string ColumnID = "ID";
Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
4

Try to change this

public static readonly string ColumnID = "ID";

to

public const string ColumnID = "ID";
Community
  • 1
  • 1
Żubrówka
  • 730
  • 1
  • 10
  • 24
3

Just for completeness, here are the three valid default values for an optional argument: ( from: MSDN: Named and Optional Arguments)

  1. a constant expression
  2. an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct; (note: only the parameterless constructor can be used)
  3. an expression of the form default(ValType), where ValType is a value type.
Ben
  • 113
  • 1
  • 5
3

readonly

The value of a readonly field can be changed (in a constructor). You need a const.

AakashM
  • 62,551
  • 17
  • 151
  • 186
2
public const string ColumnID = "ID";
archil
  • 39,013
  • 7
  • 65
  • 82