Search code examples
c#genericsinheritancepropertiesinner-classes

Cannot access inherited property if class has nested class of same name


I want to access a property of some class of mine, but get compiler error "CS0572 - Cannot reference a type through an expression".

I have the following setup

public interface IHelper {
    void DoHelp();
}

public abstract class ClassWithHelperBase<THelper> where THelper : IHelper {
    public THelper Helper { get; }
}

public class ClassWithHelper : ClassWithHelperBase<ClassWithHelper.Helper> {
    // use a nested class, since there will be n classes deriving from ClassWithHelper and giving each helper a readable name (in this example ClassWithHelperHelper) is ugly
    public class Helper : IHelper {
        public static void SomeStaticMethod() { }
        public void DoHelp() { }
    }
}

public class Test {
    private ClassWithHelper myClass;

    public void DoTest() {
        ((ClassWithHelperBase<ClassWithHelper.Helper>) myClass).Helper.DoHelp(); // this works, but is ugly
        myClass.Helper.DoHelp(); // what I want, but it's not working
        //myClass.Helper.SomeStaticMethod(); // funnily IDE supposes static methods here even though the resulting code is invalid, since I am (obviously) not referencing the class type
    }
}

The interface is unnecessary for reproduction, I added it for clarity.

Note: I do not want to call a static method, I just added it, to show the IDE mixes up the member and the class qualifier.

Is there a way to access the property Helper of myClass, without casting myClass or renaming the nested class? Aka: Why can't the compiler distinguish the member and the nested class?


Solution

  • The problems is due to name collision between Helper class (type) and Helper property. Try this

    public interface IHelper
    {
        void DoHelp();
    }
    
    public abstract class ClassWithHelperBase<THelper> where THelper : IHelper 
    {
        public THelper Helper { get; set; }
    }
    
    public class ClassWithHelper : ClassWithHelperBase<ClassWithHelper.CHelper> 
    {
        // use a nested class, since there will be n classes deriving from ClassWithHelper and giving each helper a readable name (in this example ClassWithHelperHelper) is ugly
        public class CHelper : IHelper 
        {
            public static void SomeStaticMethod() {}
            public void DoHelp() { }
        }
    }
    
    public class Test 
    {
        private ClassWithHelper myClass;
    
        public void DoTest() {
            myClass.Helper.DoHelp();
            ClassWithHelper.CHelper.SomeStaticMethod();
        }
    }
    

    Here I renamed Helper class to the CHelper, so compiler can now distinguish class and property and thus the line myClass.Helper.DoHelp(); now works without cast.

    If a "do not rename nested class" requirement is absolutely mandatory, then the problem may be also solved by renaming the Helper property in the base class to avoid name collision. However, I can't imagine better name for the property.

    Unfortunately, for the static method, you can't reference myClass instance. So, you will need reference the whole type.