如何将对嵌套类成员的访问限制为封闭类?

Tho*_*que 58 c# nested-class access-levels

是否可以指定封闭类可以访问嵌套类的成员,而不是其他类?

这是问题的一个例子(当然我的实际代码有点复杂......):

public class Journal
{
    public class JournalEntry
    {
        public JournalEntry(object value)
        {
            this.Timestamp = DateTime.Now;
            this.Value = value;
        }

        public DateTime Timestamp { get; private set; }
        public object Value { get; private set; }
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

我想阻止客户端代码创建实例JournalEntry,但Journal必须能够创建它们.如果我将构造函数Journal设为public,那么任何人都可以创建实例......但如果我将其设为私有,则无法执行!

请注意,JournalEntry该类必须是公共的,因为我希望能够将现有条目公开给客户端代码.

任何建议将不胜感激!


更新:感谢大家的意见,我最终选择IJournalEntry了私人JournalEntry课程实现的公共界面(尽管我的问题是最后一个要求......)

Ray*_*rns 80

实际上,这个问题有一个完整而简单的解决方案,不涉及修改客户端代码或创建接口.

对于大多数情况,此解决方案实际上比基于接口的解决方案更快,并且更容易编码.

public class Journal
{
  private static Func<object, JournalEntry> _newJournalEntry;

  public class JournalEntry
  {
    static JournalEntry()
    {
      _newJournalEntry = value => new JournalEntry(value);
    }
    private JournalEntry(object value)
    {
      ...
Run Code Online (Sandbox Code Playgroud)

  • 我在这种方法中发现的问题是因为.NET中的静态构造函数被懒惰地调用,你可能会发现自己的`_newJournalEntry`为null - 但是`System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor`可以节省一天.:) (7认同)
  • 不要打电话给我们,我们会打电话给你。然后您可以给我们打电话。 (4认同)
  • 不错的原创方法......我必须记住那一个.谢谢 ! (3认同)
  • 这踢了一些战利品.谢谢. (3认同)
  • 漂亮.接受的答案有相同的一般想法,但它出现在一堆其他替代品的底部,所以看看这里! (2认同)
  • @Regent 也可以抛出一个空的 static void 方法来调用静态 ctor。不漂亮,但有效。 (2认同)

Gri*_*zly 47

如果您的类不是太复杂,您可以使用公开可见的接口并使实际的实现类为私有,或者您可以为JornalEntry该类创建一个受保护的构造函数,并使用一个公共构造函数JornalEntryInstance派生的私有类JornalEntry实际上由实例化实例化你的Journal.

public class Journal
{
    public class JournalEntry
    {
        protected JournalEntry(object value)
        {
            this.Timestamp = DateTime.Now;
            this.Value = value;
        }

        public DateTime Timestamp { get; private set; }
        public object Value { get; private set; }
    }

    private class JournalEntryInstance: JournalEntry
    { 
        public JournalEntryInstance(object value): base(value)
        { }
    }
    JournalEntry CreateEntry(object value)
    {
        return new JournalEntryInstance(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的实际类太复杂而无法执行其中任何一项,并且您可以使构造函数不完全不可见,则可以将构造函数设置为内部,以使其仅在程序集中可见.

如果这也是不可行的,你总是可以将构造函数设为私有,并使用反射从日记类中调用它:

typeof(object).GetConstructor(new Type[] { }).Invoke(new Object[] { value });
Run Code Online (Sandbox Code Playgroud)

现在我考虑一下,另一种可能性是在内容类中设置的包含类中使用私有委托

public class Journal
{
    private static Func<object, JournalEntry> EntryFactory;
    public class JournalEntry
    {
        internal static void Initialize()
        {
            Journal.EntryFactory = CreateEntry;
        }
        private static JournalEntry CreateEntry(object value)
        {
            return new JournalEntry(value);
        }
        private JournalEntry(object value)
        {
            this.Timestamp = DateTime.Now;
            this.Value = value;
        }

        public DateTime Timestamp { get; private set; }
        public object Value { get; private set; }
    }

    static Journal()
    {
        JournalEntry.Initialize();
    }

    static JournalEntry CreateEntry(object value)
    {
        return EntryFactory(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该为您提供所需的可见性级别,而无需借助慢速反射或引入其他类/接口

  • 第一种方法有一个很大的缺点:其他类也可以从JournalEntry继承,然后调用构造函数. (5认同)
  • @TimPohlmann 您现在可以将 JournayEntry ctor 设为“private protected”,这应该可以为继承者提供一些防御。 (2认同)

Sam*_*ell 20

创建JournalEntry一个私有嵌套类型.任何公共成员仅对封闭类型可见.

public class Journal
{
    private class JournalEntry
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果需要使JournalEntry对象可用于其他类,请通过公共接口公开它们:

public interface IJournalEntry
{
}

public class Journal
{
    public IEnumerable<IJournalEntry> Entries
    {
        get { ... }
    }

    private class JournalEntry : IJournalEntry
    {
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 12

一种更简单的方法是使用internal构造函数,但通过提供只有合法调用者才能知道的引用来使调用者证明他们是谁(我们不需要关注非公开反射,因为如果调用者有访问权限对于非公开的反思,我们已经失去了战斗 - 他们可以private直接访问构造函数); 例如:

class Outer {
    // don't pass this reference outside of Outer
    private static readonly object token = new object();

    public sealed class Inner {
        // .ctor demands proof of who the caller is
        internal Inner(object token) {
            if (token != Outer.token) {
                throw new InvalidOperationException(
                    "Seriously, don't do that! Or I'll tell!");
            }
            // ...
        } 
    }

    // the outer-class is allowed to create instances...
    private static Inner Create() {
        return new Inner(token);
    }
}
Run Code Online (Sandbox Code Playgroud)