如何在C#中限制对其容器的嵌套类的访问?

时间:2017-03-22 20:11:35

标签: c# inner-classes access-levels

我有一个配置类商店应用程序配置。目前我正在使用静态类。一些配置与一个主题相关,所以我想将它们组织成一个嵌套类,所以我可以引用这样的配置:

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 个答案:

答案 0 :(得分:7)

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

这实际上是您提出的更普遍问题的一个特例:我们如何将内部类的某些成员标记为只能 到外部类,但不< / em>到那个类之外的任何东西?

如何做到这一点并不明显,但这非常容易。解决方案的关键是要记住接口可能是私有实现细节。 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的公共成员之外无法看到任何其他内容,因为他们查看私有成员所需的界面本身就是私有的。

答案 1 :(得分:2)

我投票支持埃里克的答案,但是想把它作为'需要考虑的事情'。

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。

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

因此,如果您的分组目标主要是关于公共界面 - 您如何获得价值 - 这种方法更简单,但如果您的目标也是内部分组......那么显然它无法实现。

答案 2 :(得分: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的实例,但无法修改您的实例。

答案 3 :(得分:0)

如果这是您想要的方法,我会看到两个选项:

  1. 您将配置文件加载和解析的所有逻辑提取到一个单独的项目(库)中,而不是标记您的setter 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;
        }
    }
    
  3. 我经常使用的另一个选项是将配置的不同部分的解析封装到子类中。您在构造函数中提供该信息,并且该类初始化自身。 (就像Evk commented in the meanwhile