3

I have this situation: I need class2(string) constructor to only be accessible from within the class1 methods and not from external 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) 
        {   
        }
    }
}

I'm trying to validate a user, the class2() create an empty instance of the user class while the class2(...) login the user. now I have class1 login method access that can be called from my pages, and i dont want that any of my pages directly calls my class2(...) login but must all pass from class1.access() that returns the class2 with user informations.

edit: the purpose of this is to create a safe login procedure, I do not want to expose my login and make it accessible directly from my pages, I want that my pages pass from the logic of class1.access() which will make considerations on how/if to login a user and return and empty class2 if the login fail with also class2.valid=false; or will return a class2 with all the informations from the user. I need to access and create and empty class2 from my pages since I pass it as out param in my class1.access(login_credentials credentials, out class2 user_data)

elnath78
  • 137
  • 1
  • 13
  • 3
    How about just declare the class private not public? – Andrei Aug 25 '15 at 17:08
  • 1
    @Andrei: I think the OP wants `new class2()` to be callable from anywhere but `new class2(string)` to only be accessible by class1. Notice the parameterless ctor is public. I'm not familiar with nested classes, so I'm not sure if making class2 private would prevent that ctor from being callable. – BoltClock Aug 25 '15 at 17:11
  • 1
    @BoltClock, i see. Yeah, I've probably missed that. In that case the best bet would be probably a factory method, at least sounds cleaner than some tricks with nested classes – Andrei Aug 25 '15 at 17:18
  • 1
    Can you share more information about why `class2` is nested, and why/whether the parameterless constructor needs to be public, why the other constructor needs to be accessible to `class1`, etc? As it stands, you can't do exactly what you're asking. It's likely that there's a better approach, but it's hard to make a recommendation without knowing what parts of this design are flexible. – StriplingWarrior Aug 25 '15 at 17:22
  • you ned to use a method. constructor method and not *ctor* itself. – Tigran Aug 25 '15 at 17:23
  • I'm trying to validate a user, the `class2()` create an empty instance of the `user` class while the `class2(...)` login the user. now I have `class1` login method `access` that can be called from my pages, and i dont want that any of my pages directly calls my `class2(...)` login but must all pass from `class1.access()` that returns the `class2` with user informations. – elnath78 Aug 25 '15 at 17:30
  • 1
    This appears to be an [XY Problem](http://meta.stackexchange.com/a/66378/171858), that is, you believe that preventing accessibility to the constructor solves a problem, but you have not described that problem. Most likely this can be solved without changing the accessor and using and interface or abstract class, but you have not included how class2 is going to be used so I cannot give you a solution. – Erik Philips Aug 25 '15 at 17:31
  • @elnath78 don't add question content as a comment. You have access to edit your question, please add the content there so users do not have to read comments to understand and answer the question. – Erik Philips Aug 25 '15 at 17:32
  • Exampls: `myloginpage` create a new `class2()` and empty user class with all values set to 0/null/string.empty() etc.. now call `class1.access()' passing id and password, this class calls `class2(...)` and validate the user and return the `class2` with values back to `myloginpage` so I do not expose the login procedure to my public pages. – elnath78 Aug 25 '15 at 17:33
  • If you aren't passing class2 around, then there is no reason for it to exist, the logic should just be in class1. – Erik Philips Aug 25 '15 at 17:54
  • @ErikPhilips yes I'm using `class2()` to istance an empty user class – elnath78 Aug 25 '15 at 18:26

3 Answers3

2

As far as I know, there's no direct mechanism to restrict access to a nested class's constructor to its wrapping class only. There are a couple of code redesign workarounds though that you could consider. If you're willing, you can make the constructor internal:

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

    public class class2 
    {
        public class2() 
        { 
        }

        internal class2(string p) 
        {   
        }
    }
}

This will restrict access to that constructor to the assembly that class2 resides. If all you want to do is restrict access for third parties consuming your libraries, then that might be a viable solution.

Another option is you can take advantage of the fact that the nested class2 can access private members of class1. In this way you can promote a factory method to "expose" the constructor:

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) 
        {   
        }
    }
}

Honestly, this is a bit obtuse, but it will enforce the rules ultimately making it so that class1 and class2 are the only types that can ever access the class2(string p) constructor. I think your best bet though is to consider a possible change of your code design.

Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • with `internal` i can still access the construction with arguments from my other pages, doesn't seems to resolve the issue. Ill updae the question with more details ad per my previous comments. – elnath78 Aug 25 '15 at 17:39
  • @elnath78: Then if you want to restrict access from within your own library (so you don't accidentally shoot yourself in the foot) then my second solution should work as well. – Chris Sinclair Aug 25 '15 at 17:40
  • @ChrisSinclair pls see my edit to my question, maybe it makes more sense now, thanks. – elnath78 Aug 25 '15 at 17:46
  • 1
    @elnath78: I would consider something along the lines of [@ErikPhilips' answer](http://stackoverflow.com/a/32210583/1269654). Alternatively, consider moving this validation logic to another project in your solution so you can take advantage of using `internal` accessors restricting unintended access from your web page UI layer project. – Chris Sinclair Aug 25 '15 at 17:51
1

You can't do it with normal constructs (use of access modifiers), but one way you can do it is with reflection:

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) { }
    }
}

With reflection, you could invoke private or protected constructors using the BindingFlags.NonPublic to find the appropriate constructor. After that you .Invoke it to obtain a reference to the object and cast it for strong typing.

Ron Beyer
  • 11,003
  • 1
  • 19
  • 37
1

I would use an interface in this instance. After all an interface is exactly what you are describing.

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

results:

True

False

You can pass your ICredentialsValidator around but nobody can create an ICredentialsValidator nor a class2. Simple OOP.

Although I find this to be very convoluted and overly complex. I would just use the singleton pattern and an interface for 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)
  {
    
  }
} 

Then anyone would just

Security.Instance.IsTest("test");
Community
  • 1
  • 1
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • but I need to create an empty `class2` please see my edit to my initial question – elnath78 Aug 25 '15 at 17:51
  • 2
    @elnath78: The point is that the pages don't know about "class2" (notice `class2` is `private`) and thus can't construct it. They only know about the `ICredentialsValidator` interface and through that can access the values on `class2` in a bit more indirect fashion. Erik didn't include a parameterless constructor in his sample code, but it can be trivially added. I suggest you try this out in your project and see if it works out (it probably will). – Chris Sinclair Aug 25 '15 at 17:55
  • @ChrisSinclair how can you make a parameterless constructor be accessible in a `private` class? – elnath78 Aug 25 '15 at 18:30
  • @elnath Updated Example, a private class can be constructed by the nested parent class. The private keyword prevent classes outside the parent class from creating it (it's private) just like a field, but it can be created by the parent class because it's a member. – Erik Philips Aug 25 '15 at 18:40
  • @elnath78: Make the _constructor_ `public`, keep the class `private`. The wrapping class (`class1`) can still access `class2` despite it being `private`. Anything else that _tries_ to access class2's public constructors will get an error. For example, if one of your pages tried `new class1.class2()` it would error out trying to access the `class2` _type_ before it even tried to access its constructor. EDIT: The same line of code run from from _within_ `class1` will work. – Chris Sinclair Aug 25 '15 at 18:41