1

我有一个配置类存储应用程序配置。目前我正在使用一个静态类。有些配置与一个主题相关,所以我想将它们组织成一个嵌套类,所以我可以参考如下配置:

AppConfig.Url
AppConfig.LogSettings.FileSize

我有两个选择,要么使用静态嵌套类,

public static class AppConfig
{
    public static class LogSettings
    {
        public static int FileSize {get; set;}
    }
}

或声明一个类但添加一个静态属性:

public static class AppConfig
{
    public class LogSettings
    {
        public int FileSize {get; set;}
    }

    public static LogSettings logSettings { get; private set; }
}

但是,它们都不能保护嵌套类成员 FileSize 被其他类修改,即使我private set用来保护公共静态属性。也许我不应该使用嵌套类来实现这个?有什么建议么?

4

4 回答 4

8

到目前为止给出的其他解决方案基本上需要设置一次的属性。我非常赞成不可变对象,但它们并不总是实用的;是否有可能解决您的问题并使属性可变?

这实际上是您提出的更普遍问题的一个特例:我们如何将内部类的某些成员标记为只能由外部类访问,而不能由该类之外的任何东西访问

如何做到这一点并不明显,但这非常容易。解决方案的关键是记住接口可能是私有的实现细节。C# 要求基类至少与派生它的类一样可访问,但 C# 不要求实现的接口与实现它的类一样可访问!

using System;
public static class Outer
{
    private interface IPrivates
    {
        string Name { set; }
    }
    public readonly static Inner TheInner = new Inner();
    private readonly static IPrivates TheInnerPrivates = TheInner;
    public class Inner : IPrivates
    {
        public string Name { get; private set; }        
        string IPrivates.Name { set { this.Name = value; } }
    }
    public static void DoIt()
    {
        TheInnerPrivates.Name = "abc";
    }
}  
public class Program
{
    public static void Main()
    {
        Outer.DoIt();
        Console.WriteLine(Outer.TheInner.Name);
    }
}

内部的代码可以通过接口Outer访问 的私有成员。Inner外部的代码Outer只能看到 的公共成员Inner,因为他们需要查看私有成员的接口本身就是私有的。

于 2017-03-22T21:02:34.533 回答
2

我投票支持 Eric 的回答,但想把它放在这里作为“需要考虑的事情”。

public class Tester
{
    public Tester()
    {
        AppConfig.LogSettings.FileSize = 5; // compile error 
        Console.WriteLine(AppConfig.LogSettings.FileSize); // works
    }
}

public static class AppConfig
{
    // just an example of setting the value in the outer class
    private static void SetFileSize(int size)
    {
        fileSize = size; // internal only setting works
    }

    private static int fileSize; // a member of AppConfig still

    public static class LogSettings
    {
        public static int FileSize
        {
            get { return fileSize; } // internal classes can access private members of the outer class
        }
    }
}

当您从外部访问 AppConfig 时,您会获得所需的分组,但是在 AppConfig 类中,“分组”只是公开公开 getter,实际的成员变量仍然属于 AppConfig。

这是因为内部类可以访问外部类的私有成员。

因此,如果您的分组目标主要是关于公共接口 - 如何获取值 - 这种方法更简单,但如果您的目标也是在内部进行分组......那么显然它不会实现。

于 2017-03-22T21:34:16.433 回答
1

一种选择是使用嵌套类的构造函数来初始化值。例如:

public static class AppConfig {
    static AppConfig() {
        Log = new LogSettings(1);
    }

    public class LogSettings {
        public LogSettings(int fileSize) {
            FileSize = fileSize;
        }

        public int FileSize { get; private set; }
    }

    public static LogSettings Log { get; private set; }
}

然后其他类可以创建LogSettings仍然的实例,但不能修改您的实例。

于 2017-03-22T20:26:49.930 回答
0

如果这是您要采用的方法,我会看到 2 个选项:

  1. 您将有关加载和解析配置文件的所有逻辑提取到一个单独的项目(库)中,然后您可以标记您的设置器internal,其他库将无法再访问它们。

  2. 您可以实现一个更明确的属性,该属性不允许设置两次值,例如:

    private int? _fileSize;
    
    public int FileSize { 
        get { return _fileSize ?? 0; }
        set {
            if (_fileSize.HasValue) {
                throw new InvalidOperationException("You can only set the value once");
            }
            _fileSize = value;
        }
    }
    

我经常使用的另一个选项是将配置的不同部分的解析封装到子类中。您在构造函数中提供该信息,然后该类将自行初始化。(就像Evk 同时评论的那样

于 2017-03-22T20:25:21.497 回答