VS/compiler problem using generics/(inner) classes  
Author Message
Wout





PostPosted: Common Language Runtime, VS/compiler problem using generics/(inner) classes Top

Hi,

Here's a piece of code that makes VS hang:

using System;

namespace GenericsTest {
    public abstract class BaseClass<ConcreteClass> {
        public abstract ConcreteClass CreateChild();

        public class Inner : BaseClass<Inner>{
            Inner CreateChild() {
                return new Inner();
            }
        }
    }
}

With similar code which doesn't make VS hang I can't use BaseClass.Inner as a method parameter because the compiler will yield the following error:

Error 2 Inconsistent accessibility: parameter type 'CadLib.Drawing.DrawContext.Wireframe' is less accessible than method 'CadLib.Model.Entities.DxfXLine.DrawInternal(CadLib.Drawing.DrawContext.Wireframe)' C:\Wout\view3\src\CadLib\Model\Entities\DxfXLine.cs 90 24 CadLib

The error seems false because all the classes involved are public... compiler bug

Kind regards,

Wout

PS: modifying to the following does compile:

using System;

namespace GenericsTest {
    public interface IBaseClass<ConcreteClass> {
        public ConcreteClass CreateChild();
    }
   
    public class BaseClass  {

        public class Inner : IBaseClass<Inner>{
          Inner CreateChild() {
            return new Inner();
          }
        }
    }
}



.NET Development10  
 
 
TaylorMichaelL





PostPosted: Common Language Runtime, VS/compiler problem using generics/(inner) classes Top

If the compiler hangs then it is an issue that should be reported to MS. However it'll probably not be a high priority unless it has consequences beyond just the code you posted.

Time to voice my opinion. Are you purposefully trying to test the compiler or something In my opinion it shouldn't compile at all. What do you gain by nesting a class within another class and deriving from it I can't even imagine a situation where this is remotely useful. A nested type should provide implementation support to the parent type, not derive from it. Even more important is that a nested type should almost never be (actually I can't think of a situation where it wouldn't be) anything beyond private or protected. Therefore I would consider your example to be a nice theoretical issue but not one that would ever occur in a real-world application. I could be wrong though. Just my opinion.

Michael Taylor - 10/30/06


 
 
Wout





PostPosted: Common Language Runtime, VS/compiler problem using generics/(inner) classes Top

Somehow I'm not receiving reply notifications, wierd.

Anyways, it wasn't a contrived piece of code, though I cleaned it up to make it understandable on the forum. The global idea was to have a ICloneable<T> interface, where a class that implements the interface has a typesafe Clone method, that doesn't require a cast of the return value. Makes perfect sense so far doesn't it This is the core idea that I wanted to work. The rest is just the context in which I needed it to work. I had no need for an extra interface, so I wanted the class itself to be generic and contain the method signature. Should work, right And in my particular case I had inner classes inheriting from the outer class. This style works nicely when the class nesting hierarchy matches the inheritance hierarchy. The advantage is that the autocompletion helps the programmer navigating the inheritance tree. I use it in my CadLib library where there are e.g. several DxfDimension flavors: DxfDimension.Linear, DxfDimension.Aligned. I prefer this style over having separate classes DxfLinearDimension and DxfAlignedDimension. So my design patterns are not according to the generally accepted design guidelines, but some thought went into it before laying those aside.

I admit, there are probably not a whole lot of cases where you'd need to apply this technique. On the other hand I wouldn't say it's extremely far fetched either.

Thanks for the answer anyway,

Wout


 
 
TaylorMichaelL





PostPosted: Common Language Runtime, VS/compiler problem using generics/(inner) classes Top

I agree with the concept but I'll go back to the implementation you provided and reword it. You are attempting to create a concrete class implementation of an abstract base class within itself. A class isn't abstract if it contains a full concrete implementation of itself. In this case you'd be better creating an extensible base class that provides a default implementation. Let's follow this road a little further. Suppose I create a new class deriving from the base class. I now have a concrete implementation of the base class'es nested class yet I have no use for it. Furthermore if anyone wanted to use it then they would have to prefix it with the base class name first which means more typing.

To meet your original requirements I'd do the following:

public abstract class BaseClass<type>
{
public abstract type CreateChild ( );
}

public class Inner : BaseClass<type>
{
public override type CreateChild ( )
{
};
}

Now instead of doing this:

BaseClass.Inner inner = new BaseClass.Inner();

I'd do this:

Inner inner = new Inner();

Less typing, more clear. Even better I haven't burdened users of my abstract class with an implementation they don't care about. If I'm going to provide an implementation default then I wouldn't make the base class abstract.

So, in a nutshell, I agree with the concept but I don't feel that your code is significantly easier to use or even maintainable over the existing paradigms in use. Additionally your paradigm would require additional overhead in all derived classes even if they didn't need base class functionality. IMHO.

Michael Taylor - 11/21/06


 
 
Wout





PostPosted: Common Language Runtime, VS/compiler problem using generics/(inner) classes Top

Hi Michael,

Nice info about an abstract class not able to have a concrete inner class. Couldn't have guessed from the error message. But, nevertheless, the error also doesn't seem to be related to that... the following piece of code (non-abstract class) has the same problem:

using System;

namespace GenericsTest {
public class BaseClass<ConcreteClass> {
public virtual ConcreteClass CreateChild() {
throw new Exception();
}

public class Inner : BaseClass<Inner>{
Inner CreateChild() {
return new Inner();
}
}
}
}

Anyways, the argument doesn't have any substance if we're not discussing a concrete case. Your less typing argument holds in the fictional example, but not in my real world project. And my abstract class isn't a pure abstract class, it does have some implementation. Further I'm not applying the paradimn everywhere, it's not really a black and white where one style is clearly better than the other.

The case where I do like it, is where I have about 6 flavors of dimensions: linear, aligned, 3-point angle, 4-point angle and some more. So without using inner classes they'd be named LinearDimension, AlignedDimension etc. I like to type to be able to type Dimension, press the dot, and see what kind of dimensions I can use. As far as the maintainability argument goes: you'd just put each inner class in it's own .cs file, using partial classes. So this gives the advantage that all the subclasses will be nicely grouped together in the solution explorer. In the other case they would be spread all over the folder.

In another case I could have applied it, but didn't. It's where there are 2 polyline flavors, plain and spline. I chose to define a PolylineBase here and have a Polyline and a SplinePolyine derive from it. Here I preferred having a class Polyline over e.g. having Polyline.Plain and Polyline.Spline. Plain polylines would be used in most of the cases, so that made me use a different pattern here...

So, for the time being I'm still happy enough with the paradigm to have an extra few artificial interfaces.

Wout