Class 访问者级别 - 如何做到这一点?

Class accessor level - how to make this possible?

我遇到这种情况:我需要 class2(string) 构造函数只能从 class1 方法内部访问,而不是从外部 classes:

public class class1 
{
    public void access() 
    { 
        //want to make class2(string) be accessible only from here
    }


    public class class2 
    {
        public class2() 
        { 
        }

        private class2(string p) 
        {   
        }
    }
}

我正在尝试验证用户,class2() 创建用户的空实例 class 而 class2(...) 登录用户。现在我有 class1 可以从我的页面调用的登录方法访问权限,我不希望我的任何页面直接调用我的 class2(...) 登录但必须全部从 class1.access() 传递 returns class2 与用户信息。

编辑:这样做的目的是创建一个安全的登录程序,我不想公开我的登录信息并使其可以直接从我的页面访问,我希望我的页面从 class1.access() 的逻辑传递,这将考虑 how/if 以登录用户和 return 并且如果登录失败也为 class2.valid=false; 或空 class2将 return a class2 包含来自用户的所有信息。我需要从我的页面访问、创建和清空 class2,因为我在我的 class1.access(login_credentials credentials, out class2 user_data)

中将它作为 out 参数传递

你不能用普通的构造(使用访问修饰符)做到这一点,但你可以做到的一种方法是反射:

public class Outer
{
    public Inner GetInstanceOfInner(string s)
    {
        var innerInstance = 
            typeof(Inner).GetConstructor(
                 System.Reflection.BindingFlags.NonPublic,  //Search for private/protected
                 null,   //Use the default binder
                 new[] { typeof(string) },  //Parameter types in the ctor
                 null)   //Default binder ignores this parameter
                 .Invoke(new[] { s }) as Inner; //Create and cast

        return innerInstance;
    }

    public class Inner
    {
        public Inner() { }
        private Inner(string s) { }
    }
}

通过反射,您可以使用 BindingFlags.NonPublic 调用私有或受保护的构造函数来找到合适的构造函数。之后你 .Invoke 它获取对象的引用并将其转换为强类型。

据我所知,没有 direct 机制来限制对嵌套 class 的构造函数的访问仅限于其包装 class。尽管您可以考虑一些代码重新设计的解决方法。如果你愿意,你可以使构造函数 internal:

public class class1 
{
    public void access() 
    { 
        var c = new class2("asdf");
    }

    public class class2 
    {
        public class2() 
        { 
        }

        internal class2(string p) 
        {   
        }
    }
}

这将限制对 class2 所在的 assembly 的构造函数的访问。如果您只想限制 第三方 使用您的库的访问权限,那么这可能是一个可行的解决方案。

另一种选择是您可以利用嵌套 class2 可以访问 class1private 成员这一事实。通过这种方式,您可以将工厂方法提升为 "expose" 构造函数:

public class class1 
{
    private static Func<string, class2> CreateNewClass2;

    static class1()
    {
        //this just forces the static constructor on `class2` to run.
        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(class2).TypeHandle);
    }

    public void access() 
    { 
        class2 c = CreateNewClass2("asdf");
    }

    public class class2 
    {
        static class2()
        {
            //this is where we create a delegate exposing/promoting our private constructor
            class1.CreateNewClass2 = p => new class2(p);
        }

        public class2() 
        { 
        }

        private class2(string p) 
        {   
        }
    }
}

老实说,这有点迟钝,但它最终会强制执行规则,因此 class1class2 只有 类型可以访问 class2(string p) 构造函数。我认为你最好的选择是考虑对你的代码设计进行可能的更改。

在这种情况下我会使用接口。毕竟界面正是您所描述的。

DotNetFiddle.net Example

using System;

public class Program
{
    // Properties you want others to have access too
    public interface ICredentialsValidator
    {
        bool IsTest(string userName);
    }

    public static void Main()
    {
        var b = new PublicClass().GetCredentialsValidator();

        Console.WriteLine(b.IsTest("test"));
        Console.WriteLine(b.IsTest("blah"));
    }

    public class PublicClass
    {
        public ICredentialsValidator GetCredentialsValidator()
        {
            return new PrivateClass();
        }

        private class PrivateClass : ICredentialsValidator
        {
            public bool IsTest (string userName)
            {
                return userName == "test";
            }
        }
    }
}

结果:

True

False

您可以传递您的 ICredentialsValidator,但没有人可以创建 ICredentialsValidatorclass2。简单的 OOP。

尽管我发现这非常令人费解且过于复杂。我只想使用单例模式和 Liskov's Substitution Principle:

的接口
public interface ISecurity
{
  bool IsTest(string userName);
}

public sealed class Security : ISecurity
{
  private static readonly Lazy<Security> lazy =
    new Lazy<Security>(() => new Security());
 
  public static ISecurity Security Instance { get { return lazy.Value; } }

  private Singleton()
  {
  }

  public bool IsTest(string userName)
  {
    
  }
} 

那么任何人都会

Security.Instance.IsTest("test");