【问题标题】:Const String From Settings来自设置的常量字符串
【发布时间】:2014-04-09 11:39:01
【问题描述】:

我想从 Settings 中设置一个 const 字符串。

如果我将来想更改程序语言,这很容易; 只需要修改相应的设置!

尝试这个时:

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

我得到这个错误:

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

有什么想法吗?

【问题讨论】:

  • Default 属性是否只有一个setter?
  • @ChrisSinclair 设置处理这个并且默认有getter:'public static Settings Default { get { return defaultInstance; } }'
  • (关于您在已删除答案中的评论,您计划将其用于方法参数默认值)然后您只需稍微更改您的代码。默认值必须是常量。您不能从配置文件中设置常量。尝试使用方法重载,而不是未指定这些参数的重载使用这些默认值包装它。
  • 一个常量字段应该用编译时常量值初始化。你不能在运行时初始化它。
  • @ChrisSinclair 感谢您的解释。

标签: c# settings constants


【解决方案1】:

由于您打算将其用作可选方法参数的默认值,即:

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

这个constString 必须是一个编译时常量。来自the MSDN page for "Named and Optional Arguments"

默认值必须是以下表达式类型之一:

  • 一个常量表达式;

  • new ValType() 形式的表达式,其中 ValType 是值类型,例如枚举或结构;

  • default(ValType) 形式的表达式,其中 ValType 是值类型。

因此,实际上没有办法在运行时从配置文件中读取值,然后将其用作可选参数

一种解决方法是将您的constString 声明为readonly 字段:

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

然后使您的可选参数成为必需参数,并为您的方法创建一个包装overload,该方法不采用该参数。该重载反过来调用旧方法,并在运行时解析默认值:

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

public void Foo()
{
    Foo(constString); //calls the other overload with the default value
}

【讨论】:

  • 另一种解决方法——如果重载看起来过于混乱——是在参数列表中设置默认值null,并在实现中应用“真正的默认值”(constString) Foo.
  • @PJTraill:您的意思是检查参数是否为null,是否将其设置为配置值?那是if(something == null) something = Properties.Settings.Default.constStringText;?一个绝对可以做到这一点,尽管你开始引入魔法值(你必须记录/知道null 将提取特殊的配置值),并且只有在null 不是第一个有效输入的情况下才会起作用地点。
  • 这就是我的意思,或者在某处使用something != null ? something : constStringText。 (我从来没有尝试分配给一个论点。)它当然有它的缺点。 null 的含义真的应该在文档 cmets 中——但如果你有几个这样的论点,重载路由也是坏消息。带有许多参数的重载也很无聊,因为源代码被一小段代码之间的文档 cmets 淹没了!
【解决方案2】:

在 99% 的情况下,此错误与错误的命名空间有关。 你可能已经生成了一些你正在使用Properties.Settings.Default的类

解决方案:检查该类文件中的命名空间。它必须与存储该特定设置的 App.config (Web.config) 中的标记名称相同。

【讨论】:

  • 我不相信,我当然没有涉及命名空间,并且 消息非常有意义 如果@,初始值肯定是不可接受的987654322@ 直到运行时才被评估,正如 Chris Sinclair 的回答中所解释的那样。
【解决方案3】:

虽然Chris Sinclair’s answerconst 成员必须具有值类型并且在编译时可评估,因此使用readonly)是正确的,但我想解释这些限制并回答隐含的问题编译器消息是什么意味着,尽管令人失望的评论似乎只是编译器中的错误

错误信息

属性或索引器“Properties.Settings.Default”无法在此上下文中使用,因为它缺少 get 访问器。

这条消息表明表达式Properties.Settings.Default 可以通过添加一个getter(可能还有其他东西)来接受——据我所知,这是完全错误的。毕竟,一方面,正如提问者向我们保证的那样1,有一个 getter,另一方面,正如 Chris 解释的那样,表达式无效的原因是在编译时无法评估 -时间,而且永远不可能,因为它取决于运行时配置。

大概这条消息是针对其他情况的,这里误用了。

1 我在 MSVS 2013 中也看到了这一点,当默认参数值引用了一个确实有 getter 的属性时——但至少它还报告了“默认参数值'<parname>' 必须是编译时常量”。

值类型的限制

const 成员和默认参数值对值类型的限制(如 C# 5.0 语言规范,2012 年)似乎并非完全不可避免,但其他语言设计决策的可理解结果。

  • 引用类型可以有一个可在编译时评估的构造函数,但这不受支持;这可能是因为该语言没有提供任何方法来表明引用的对象是不可变的,甚至没有提供引用类型对象不可变的概念。 (请记住:对对象的不可变引用不一定是对不可变对象的引用!)
  • 引用 static 方法的委托值也可以视为在编译时完全确定,如果支持该概念,那些绑定到不可变对象的委托值也是如此。
  • 不可变数组作为常量值听起来很容易支持。
  • 常量成员¹ 和 (我相信)² 默认参数值被指定为 类的“接口”的一部分,因为它们的值是在编译时确定并使用该类硬编码到生成的代码中。

问题的解决

  • 你可以用(static)readonly constString代替const constString,明确表示虽然值不会改变,但直到运行时,在类或对象初始化时(如 Chris 的回答)。
  • 如果您想将表达式用作可选参数的默认值,它必须是真正的编译时常量,留给您两种可能性:

    • 声明过载,如 Chris 的回答,例如:

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

      • 这通常是更简单的解决方案,但如果您有很多这样的参数并因此有很多重载,所有这些都带有文档 cmets,则可能会使您的代码和界面变得混乱。
    • 使用null 作为默认约定,并在您的方法中解释它:

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

      • 这显然只有在 null 不是 Foo(string) 的受支持参数时才有效,并且绝对应该在文档 cmets 中加以说明。
    • 也许:应用Optional 属性,如这个问题:behaviour of Optional attribute:

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

      • 我没有使用或研究过这个 - 文档似乎相当稀疏​​ - 但它似乎很棘手,并且只产生默认的 = null,除非 null 可能是 Foo(string) 的支持参数。

参考文献

¹ 语言规范 5.0 §10.5.2.2 10.5.2.2 常量和static readonly 字段的版本控制
² 我记得读过这篇文章,但在语言规范中没有找到它。

【讨论】:

    【解决方案4】:

    我最近遇到了这种情况,在寻找解决方案时,我偶然发现了这个页面。根据上面的示例,我能够像这样解决我的问题:

    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);
    

    只是想分享。

    【讨论】:

    • 这里的相关点是readonly 而不是const(正如克里斯辛克莱的回答所建议的那样)而不是String.Format 的调用。
    • @PJTrail - 只是为了澄清我没有在这里强调 String.Format,我在发布此答案时忽略了 Chris Sinclair 的建议。当然它是只读的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多