How to create a constructor that is only usable by

2020-08-09 11:33发布

As far as I know, in C#, there is no support for the "friend" key word as in C++. Is there an alternative way to design a class that could achieve this same end result without resorting to the un-available "friend" key-word?

For those who don't already know, the Friend key word allows the programmer to specify that a member of class "X" can be accessed and used only by class "Y". But to any other class the member appears private so they cannot be accessed. Class "Y" does not have to inherit from class "X".

10条回答
干净又极端
2楼-- · 2020-08-09 11:40

You can access private members/methods using Reflection.

Since it's got the design tag, I never particularly liked the friend keyword. It pierces encapsulation and that always felt dirty to me.

查看更多
一夜七次
3楼-- · 2020-08-09 11:40

This has a bit of a smell. There are other plenty of other ways to achieve implementation hiding in C#. Limiting construction to only specific classes does not achieve all that much.

Could you please provide more information as to the purpose of this requirement? As already answered, internal is the closest match for limiting accessibility to the class. There are ways to build on top of that depending on the purpose.

查看更多
Rolldiameter
4楼-- · 2020-08-09 11:44

No. The closest you have is an internal constructor, or a private constructor and a separate factory method (probably internal, so you haven't saved much).

查看更多
ら.Afraid
5楼-- · 2020-08-09 11:44

As a workaround, I suppose you could create a conditional in your constructor that uses reflection.

For example, if Class1's constructor must be called by Class2:

public Class1()
{
    string callingClass = new StackFrame(1).GetMethod().DeclaringType.Name;

    if (callingClass != "Class2")
    {
        throw new ApplicationException(
            string.Concat("Class1 constructor can not be called by ",
            callingClass, "."));
    }
}

EDIT:

Please note that I would never actually do this in "real" code. Technically it works, but it's pretty nasty. I just thought it was creative. :)

查看更多
一夜七次
6楼-- · 2020-08-09 11:48

This is how I solved it. I'm not sure if it's the "right" way to do it, but it required minimal effort:

public abstract class X
{
    // "friend" member
    protected X()
    {
    }

    // a bunch of stuff that I didn't feel like shadowing in an interface
}

public class Y
{
    private X _x;

    public Y()
    {
        _x = new ConstructibleX();
    }

    public X GetX()
    {
        return _x;
    }

    private class ConstructibleX : X
    {
        public ConstructibleX()
            : base()
        {}
    }
}
查看更多
该账号已被封号
7楼-- · 2020-08-09 11:48

What about just having it explicity implement an interface that is only visible to a certain class?

Something like:

public void IFreindOfX.Foo() //This is a method in the class that's a 'friend' to class X.
{
   /* Do Stuff */
}

and then make sure IFriendOfX is visible to class X. In your X class you'd call the method by first casting X to IFriendOfX then calling Foo(). Another advantage is that is is fairly self documenting... that is, it's pretty close to having the friend keyword itself.

查看更多
登录 后发表回答