Search code examples
c#.netinterfaceabstract-class

C# interface or abstract class that accepts parameter of its own field


I am trying to create an interface or an abstract class that would serve as a base for many Authorization objects.

My idea is as follows (code that does not compile but I'd like to work):

public abstract class AuthObject {
  public Enum Values;
  public abstract AuthObject AddPermission(Values permission);
}

An implementation the would look like this:

public class AuditLogManagement : AuthObject {
  private long _permissions;

  public new enum Values {
    None = 0,
    Read = 1,
    Search = 2,
    Filter = 4,
    Export = 8
  }

  public AuthObject AddPermission(AuditLogManagement.Values permission) {
    _permissions |= (long)permission;
    return this;
  }
}

The main point of my question is how to limit parameter to AddPermission() to only this object Values field (Enum) in an interface or abstract class. However I cannot find a way to do it.

Thank You for any ideas.

Edit:

A little more simplified use case to explain the requirements:

interface I {
  AddPermission(I.Values permission);
}

class A : I {
  private long _permissions;

  public enum Values {
    A_a, A_b, A_c
  }
  AddPermission (this.Values newPermission) {
    _permissions |= newPermission;
  }
}

class B : I {
  private long _permissions;

  public enum Values {
    B_a, B_b, B_c
  }
  AddPermission (this.Values newPermission) {
    _permissions |= newPermission;
  }
}

var classA = new A();
var classB = new B();
A.AddPermission(A.Values.A_a); // Allowed
A.AddPermission(B.Values.B_c); // Forbidden! B_c value equals to A_c but is not the same permission!

Solution

  • I would reach for generics:

    public abstract class AuthObject<T>
         where T : struct, IConvertible // A reasonable way to constrain to an enumeration. 
                                        // you can also use System.Enum for newer versions of C# past 7.3 I believe. 
    {
        public T Values { get; } 
        public abstract AuthObject<T> AddPermission(T permission);
    }
    
    public enum Values
    {
        None = 0,
        Read = 1,
        Search = 2,
        Filter = 4,
        Export = 8
    }
    
    public class AuditLogManagement : AuthObject<Values>
    {
        private long _permissions;
        public AuthObject AddPermission(Values permission)
        {
            _permissions |= (long)permissions;
            return this;
        }
    }
    

    The only other suggestion I would give on top of this is to name the 'T' parameter above to something a little more descriptive, like 'TPermission' since you aren't using it for the typical container class.