类访问者级别 - 如何使这成为可能?

时间:2015-08-25 17:05:14

标签: c# .net class accessor

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

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()class2(...)登录用户时创建用户类的空实例。现在我有可以从我的页面调用的class1登录方法访问,我不希望我的任何页面直接调用我的class2(...)登录,但必须全部从class1.access()传递,返回{{1}用户信息。

编辑:这样做的目的是创建一个安全的登录程序,我不希望公开我的登录并直接从我的页面访问它,我希望我的页面从逻辑中传递class2的{​​{1}}将考虑如何/如果登录用户并返回并清空class1.access()如果登录失败并同时class2或将返回class2.valid=false;所有来自用户的信息。我需要在我的网页中访问并创建并清空class2,因为我在class2

中将其作为out param传递

3 个答案:

答案 0 :(得分:2)

据我所知,没有直接机制将访问嵌套类的构造函数限制为仅包装类。您可以考虑使用几种代码重新设计的解决方法。如果您愿意,可以创建构造函数internal

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

    public class class2 
    {
        public class2() 
        { 
        }

        internal class2(string p) 
        {   
        }
    }
}

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

另一个选择是,您可以利用嵌套class2可以访问private class1成员的事实。通过这种方式,您可以提升工厂方法来“公开”构造函数:

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唯一的类型,可以访问{ {1}}构造函数。我认为你最好的选择是考虑改变你的代码设计。

答案 1 :(得分:1)

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

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获取对象的引用并将其强制输入。

答案 2 :(得分:1)

我会在这个实例中使用一个接口。毕竟,界面正是您所描述的。

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";
            }
        }
    }
}

结果:

  

     

您可以传递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");