Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement tighter encapsulation

Tags:

c#

I have a method that I want to access from only one method because it is very specific and could confuse the programmers if they "see" that method from the other parts of the class. On the other hand, for unit testing and for readability, I have to make that method.

Is there any trick to encapsulate further than usual?

Just to make sure my idea is clear: method A calls method B. I want intellisense to show method B only if I am in method A.

like image 672
Mathieu Avatar asked Sep 08 '11 14:09

Mathieu


2 Answers

If method B is only related to method A, you may want to revisit the design of the class because you could be violating the Single Responsibility Principle.

That being said, you could implement method B anonymously in the body of method A. In my opinion, this detracts from readability but does yield the behavior you want.

like image 103
Austin Salonen Avatar answered Sep 28 '22 04:09

Austin Salonen


You can check the caller of the method, execute your method body only if the caller name matches (assuming you have only 1 method of that name, otherwise you have to check the arguments as well).

Not possible to hide this in intellisense though. Furthermore create a region in the class for the DO NOT USE method.

private void Func3()
{
    // Will not execute the method body
    Func2();
}

private void Func1()
{
    // Will execute the method body
    Func2();
}

private void Func2()
{
    var callingMethodName = new StackFrame(1, true).GetMethod().Name;
    if (string.Equals(callingMethodName, "Func1"))
    {
        // Execute your method's code....
    }
}


An alternative approach using Attributes

Rather than hard coding the method name, you can create a custom attribute and mark your method with it to indicate that you are allowing this caller to execute your DoNotUseMethod().

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
class AllowedMethodAttribute : Attribute
{
    public AllowedMethodAttribute(bool methodAllowed)
    {
        this.AllowedToExecute = methodAllowed;
    }

    public bool AllowedToExecute { get; private set; }
}

And in your class use the attribute as follows,

private void AnotherNotAllowedMethod()
{
    MyDoNotUseMethod();
}

[AllowedMethod(false)]
private void NotAllowedMethod()
{
    MyDoNotUseMethod();
}

[AllowedMethod(true)]
private void MyAllowedMethod()
{
    MyDoNotUseMethod();
}

#region DoNotUseMethod 

private void MyDoNotUseMethod()
{
    var callingMethod = new StackFrame(1, true).GetMethod();
    var allowedMethodAttributes = callingMethod.GetCustomAttributes(typeof (AllowedMethodAttribute), false);
    if(allowedMethodAttributes.Length == 1)
    {
        var allowedMethodAttribute = allowedMethodAttributes[0] as AllowedMethodAttribute;
        if(allowedMethodAttribute != null && allowedMethodAttribute.AllowedToExecute)
        {
            // Execute the method body
        }
        else
        {
            Debug.Assert(false, callingMethod.Name + " is not allowed to execute this method", 
                "Mark method with AllowedMethod(true) attribute to allow execution of this method");
            // throw exception if required
        }
    }
    else
    {
        Debug.Assert(false, callingMethod.Name + " is not allowed to execute this method", 
            "Mark method with AllowedMethod(true) attribute to allow execution of this method");
        // throw exception if required
    }
}

#endregion
like image 39
Devendra D. Chavan Avatar answered Sep 28 '22 06:09

Devendra D. Chavan