Prevent “Access to a static member of a type via a derived type” when deriving classes having structs with string constants

I'm wrapping the ForgeRock REST API implementation in C#. That implementation is layered. There is a base layer on the ForgeRock level, which gets extended for each of their products (like OpenAM, OpenDJ, etc).

Parts of the API layers are definitions of http parameter names (and often a restriction on values) which I've solved with a hierarchy of KnownParameter classes, each having structs defining the parameters in structs each having one Name and potentially methods or a nested Values struct limiting or converting the values.

The code base usually is limited to one product (and the ancestor layer: ForgeRock).

From that perspective, I want to avoid the “Access to a static member of a type via a derived type” warning generated by ReSharper.

Having classes with the same names does help on the one hand (they are the same thing, just from a different namespace perspective, it compiles and works fine), on the other hand: even after renaming ForgeRock.KnownParameters into ForgeRock.KnownParametersBase ReSharper isn't happy with it. I think in this confined case, it is OK to have this kind of naming

How can I avoid that warnng while still benefiting from , and still benefit from inheritance?

Example code (also on-line with more URLs referencing the correct bits of documentation) in four pieces.

Main program exhibiting the ReSharper warning:

using System.Collections.Specialized;
using ForgeRock.OpenAM;

namespace AccessToAStaticMemberOfATypeViaADerivedType
{
    class Program
    {
        static void Main()
        {
            new NameValueCollection
            {
                {KnownParameters.PrettyPrint.Name, KnownParameters.PrettyPrint.Values.True},
                {KnownParameters.Action.Name, KnownParameters.Action.Values.Logout}
            };
        }
    }
}

ForgeRock namespace with the base KnownParameters class:

namespace ForgeRock
{
    public class KnownParameters
    {
        public struct PrettyPrint
        {
            public const string Name = "_prettyPrint";

            public struct Values
            {
                public const string False = "false";
                public const string True = "true";
            }
        }
    }
}

ForgeRock.OpenAM namespace with a descendant of the KnownParameters class.

namespace ForgeRock.OpenAM
{
    public class KnownParameters : ForgeRock.KnownParameters
    {
        public struct Action
        {
            public const string Name = "_action";

            public struct Values
            {
                public const string Logout = "logout";
            }
        }
    }
}

ForgeRock.OpenDJ namespace with a descendant of the KnownParameters class.

namespace ForgeRock.OpenDJ
{
    public class KnownParameters : ForgeRock.KnownParameters
    {
        public struct QueryFilter
        {
            public const string Name = "_queryFilter";
        }
    }
}
Jon Skeet
people
quotationmark

I think in this confined case, it is OK to have this kind of naming.

Well, personally I disagree. It's generally bad for readability when the same name means different things within a program - it's even worse (IMO) when those two names are related by inheritance. But if you really want to use this approach, there are two options:

  • Find a way of specifying ForgeRock.KnownParameters when you want to use its members, e.g.

    new NameValueCollection
    {
        {ForgeRock.KnownParameters.PrettyPrint.Name, 
         ForgeRock.KnownParameters.PrettyPrint.Values.True},
        {KnownParameters.Action.Name,
         KnownParameters.Action.Values.Logout}
    };
    

    Or you could use a using alias:

    using BaseKnownParameters = ForgeRock.KnownParameters;
    ...
    new NameValueCollection
    {
        {BaseKnownParameters.PrettyPrint.Name, 
         BaseKnownParameters.PrettyPrint.Values.True},
        {KnownParameters.Action.Name,
         KnownParameters.Action.Values.Logout}
    };
    
  • Disable the R# warning, if you're happy that you're accessing the member of ForgeRock.KnownParameters via ForgeRock.OpenAM.KnownParameters, like using ASCIIEncoding.UTF8

As an aside, I would suggest using static classes instead of structs. At the moment, someone could write:

var x = new KnownParameters.PrettyPrint.Values();

... do you want that to be legal? (It won't be using a static class.) You might also consider using enums.

people

See more on this question at Stackoverflow