3

I would like to set a const string from Settings.

In case I would like to change in the future the program language, it is quite easy; Just have to modify the appropriate settings!

When trying this:

private const string constString =   
              "-&" + Properties.Settings.Default.constStringText;  

I get this error:

The property or indexer 'Properties.Settings.Default'  
cannot be used in this context because it lacks the get accessor.  

Any idea?

user3165438
  • 2,631
  • 7
  • 34
  • 54
  • Does the `Default` property have _only_ a setter? – Chris Sinclair Apr 09 '14 at 11:43
  • @ChrisSinclair The settings handles this and Default has getter : 'public static Settings Default { get { return defaultInstance; } }' – user3165438 Apr 09 '14 at 11:45
  • (Regarding your comment in the deleted answer that you are planning to use this for method parameter default values) Then you simply have to alter your code a bit. Default values _must_ be constants. You _cannot_ set constants from a configuration file. Try using method overloading instead where the overloads that don't specify those parameters wrap it with those default values. – Chris Sinclair Apr 09 '14 at 11:48
  • A constant field should be initialized with compile-time constant value. You cannot initialize it at a runtime. – Sergey Kolodiy Apr 09 '14 at 11:49
  • I have seen this, in spite of there being a getter, for argument defaults as well, in MSVS 2013, – but at least it also reports “_Default parameter value for '____' must be a compile-time constant_”. – PJTraill Dec 02 '15 at 22:41

4 Answers4

3

Since you intend to use this as the default value for an optional method argument, that is:

public void Foo(string something = constString)
{
    //do something
}

This constString must be a compile-time constant. From the MSDN page for "Named and Optional Arguments":

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.

As such, there really is no way to read a value from a configuration file at runtime then use it for an optional argument.

One workaround would be to instead declare your constString as a readonly field:

private readonly string constString =   
              "-&" + Properties.Settings.Default.constStringText; 

Then make your optional argument required and create a wrapping overload for your method that doesn't take that parameter. That overload in turn calls the old method with the default value resolved at runtime:

public void Foo(string something) //no longer optional
{
    //do something
}

public void Foo()
{
    Foo(constString); //calls the other overload with the default value
}
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • An alternative workaround – if overloading seems like too much clutter – is to make the default value in the argument list `null`, and apply the ‘real default’ (`constString`) in the implementation of `Foo`. – PJTraill Dec 02 '15 at 16:37
  • @PJTraill: You mean do a check that if the argument is `null`, set it to the configuration value instead? That is `if(something == null) something = Properties.Settings.Default.constStringText;`? One definitely could do that, although you start introducing magic values (you would have to document/know that `null` will pull the special config value), and would only work assuming that `null` isn't a valid input in the first place. – Chris Sinclair Dec 02 '15 at 17:03
  • That’s what I meant, or use `something != null ? something : constStringText` somewhere. (I have never tried assigning to an argument.) It certainly has its downsides; the meaning of `null` __really should__ be in the documentation comments — but if you have several such arguments the overload route is also bad news. Overloads with many arguments are also a bore, as then the source is swamped by documentation comments between little bits of code! – PJTraill Dec 02 '15 at 22:36
1

This error is in 99% of cases related to a wrong namespace. You've probably generated some class in which you are using Properties.Settings.Default

Solution: check namespace in that class file. It must be the same as the name of the tag in App.config (Web.config) where that particular setting is stored.

Ognjen Stanić
  • 505
  • 8
  • 17
  • I am not convinced, I have certainly had this without namespaces being involved, and the _message makes perfect sense_ initial value is certainly unacceptable if `constString` is not evaluated till run-time, as explained in Chris Sinclair’s answer. – PJTraill Dec 03 '15 at 12:19
1

While Chris Sinclair’s answer (a const member must have value type and be evaluable at compile-time, so use readonly) is correct, I should like to explain these restrictions and answer the implicit question what the compiler message means, albeit with the disappointing remark that seems to be simply an error in the compiler.

The error message

The property or indexer 'Properties.Settings.Default' cannot be used in this context because it lacks the get accessor.

This message suggests that the expression Properties.Settings.Default could be made acceptable by adding a getter (and maybe something else) — as far as I know, that is simply wrong. After all, on the one hand, as the asker assured us1, there was a getter, and on the other, as Chris explains, the reason the expression is invalid is that is not evaluable at compile-time, and never can be, given that it depends on the run-time configuration.

Presumably this message is intended for other situations, and has been used here by mistake.

1 I have also seen this, in MSVS 2013, when a default parameter value referred to a property which did have a getter – but at least it also reported “Default parameter value for '<parname>' must be a compile-time constant”.

The restriction to value types

The restriction of const members and default parameter values to value types (as at the C# 5.0 Language Specification, 2012) appears to be not entirely inevitable, but an understandable consequence of other language design decisions.

  • A reference type can have a constructor evaluable at compile-time, but this is not supported ; perhaps this is because the language offers no way of indicating that a referenced object is immutable, nor even the concept of immutability of reference type objects. (Remember: an immutable reference to an object need not be a reference to an immutable object!)
  • Delegate values referring to static methods can also be considered fully determined at compile-time, as would those bound to immutable objects, were that concept supported.
  • Immutable arrays as constant values sound fairly easy to support.
  • Constant members¹ and (I believe)² default parameter values are specified to be part of the ‘interface’ of the class, in the sense that their values are to be determined at compile time and hard-coded into generated code using that class.

Resolution of the problem

  • You can use ( static ) readonly constString instead of const constString, to make clear that while the value will not change, it is not determined until run-time, at class or object initialisation (as in Chris’s answer).
  • If you want to use the expression as a default value for an optional parameter, it must be a true compile-time constant, leaving you two possibilities:

    • Declare an overload, as in Chris’s answer, e.g.:

      Foo() { Foo(Default); } Foo(string s) { Bar(s); }.

      • This will often be the simpler solution, but could clutter your code and interface if you have many such parameters and thus many overloads, all with documentation comments.
    • Use null as a convention for the default, and interpret that in your method:

      Foo(string s = null) { Bar(s != null ? s : Default); }.

      • This obviously only works if null is not a supported parameter to Foo(string) and should definitely be clarified in documentation comments.
    • Maybe: apply the Optional attribute, as in this question: behaviour of Optional attribute:

      Foo([Optional] string s) { Bar(etc.?); } .

      • I have not used or studied this – the documentation seemed rather sparse – but it seems tricky and to yield no more than default = null, unless perhaps null is a supported argument to Foo(string).

References

¹ Language Specification 5.0 §10.5.2.2 10.5.2.2 Versioning of constants and static readonly fields
² I recall reading this, but have not found it in the Language Specification.

Community
  • 1
  • 1
PJTraill
  • 1,353
  • 12
  • 30
0

I recently encountered this scenario, and while searching for a solution I stumbled on this page. Based on the example above, I was able to resolve my issue like this:

private static readonly String ConStr
 = string.Format("Data Source={0};Initial Catalog={1}; User ID={2}; Password={3};",
                 Properties.Settings.Default.DataSource,
                 Properties.Settings.Default.Catalog,
                 Properties.Settings.Default.UserID,
                 Properties.Settings.Default.Password);

Just wanted to share.

PJTraill
  • 1,353
  • 12
  • 30
Von Abanes
  • 706
  • 1
  • 6
  • 19
  • The relevant point here is `readonly` rather than `const` (as suggested in Chris Sinclair’s answer) rather than the call of `String.Format`. – PJTraill Dec 02 '15 at 22:48
  • @PJTrail - Just to clarify I'm not emphasizing here the String.Format, I overlook the suggestion of Chris Sinclair by the time I posted this answer. Of-course its the readonly. – Von Abanes Apr 27 '16 at 03:16