locked
Static field inheritance or design problem ? RRS feed

  • Question


  • Hello,

    I do not found any reference to that problem on forums, but I found some to a similar one, wich concerns static method inheritance, and where people often answers that this need shows a design problem.


    So, here is my problem: I want, in a class hierarchy, that every sub class defines a const field.

    For exemple, my base class is Fruit, which has a const field color set to Unknown, and 2 sub classes Apple and Banana, I want to be sure that Apple define the same const field (Green ?) and so Banana (Yellow).

    More over, I want to be able to use these field in a generic way, for exemple, for a class "Shaker<T> where T : Fruit", I want to be able to call "T.color".


    A solution could be to implement a simple Map class with a static method returning a color for a Fruit class, but Fruit, Apple and Banana are in 3 different projects, so the static map should be in a 4th projet, alone, and I don't like it...


    Thanks for your help.
    Sunday, August 1, 2010 8:46 AM

Answers

  • I don't really like it because you have to pass both the color and the type. I was hoping that maybe there's a way to split your functions into the ones that need the type parameter and the ones than only need the color. If you need both then maybe adding the map or using reflection would look a bit cleaner.

    EDIT: If you only need the type parameter to instantiate your bananas, you could add that functionality to FD instead:

      class FruitDescriptor
      {
        public abstract Color Color
        {
          get;
        }
    
        public abstract Fruit CreateInstance();
      }
    
      class BananaDescriptor : FruitDescriptor
      {
        public override Color Color
        {
          get { return Color.Yellow; }
        }
    
        public override Fruit CreateInstance()
        {
          return new Banana();
        }
      }
    

    • Marked as answer by Bleubleubleu Tuesday, August 3, 2010 12:09 PM
    Monday, August 2, 2010 10:25 PM

All replies

  • For all the things you want, you need to define it as an abstract property in the base class.
    Sunday, August 1, 2010 12:55 PM
  • I would not even make it abstract then but just a normal class as  a base so you can define the const. Abstract class is simular to an interface where you fulfill the contract of implementing all the properties/methods and define them in the child class. If you use a just a class you don't have to. It's all in design. In this case I would use a class as a base because a constant is static and has to be defined on declaration. Also I would not make it a const but rather make it readonly so you can inherit it. YOu cannot inherit a static class from the parent.

     

    Sunday, August 1, 2010 4:04 PM
  • If you don't define it as abstract, then you can't have the compiler enforce the necessity for derived classes to implement it (that's the first requirement from the OP).

    The second requirement (to have the member selected depending on the runtime type of the object) requires that the member is virtual. That's also fulfilled if it's an abstract property.

    Sunday, August 1, 2010 4:53 PM
  • Thanks for your time and your answers!

    An abstract property will force me to instanciate a Banana each time I want to know the color of a Banana. And I'm sure both of you know the color of a Banana without actually see one...

    The solution could be to deport all instanciation stuff in an Init() function, and to let the constructor empty, so I can build a useless Banana, just to check it's color, but it's still not really what I want.

     

    Monday, August 2, 2010 6:55 AM
  • You can't do it this way in dot Net. There's no way to access static members of generic type parameters (except using reflection). Perhaps we could help you to change your design if you'd provide more information. One possibility might be changing

    void DoStuff<T>()

    to

    void DoStuff(FruitDescription fd)

    where FruitDescription would be a class which holds stuff such as the fruit color. I'm not sure how much this applies to your situation though.

    Monday, August 2, 2010 8:55 AM
  • It is similar to the map class solution, but as I said, I'm not pleased with having a new project for a single class.
    Monday, August 2, 2010 9:06 AM
  • You could use the same project which defines the Fruit class instead of creating a new one. Here is a bit more complete example (FD stands for FruitDescription, I'm too lazy sorry):

    class Banana
    {
      public static FD GetDescription()
      {
        return new FD(Color.Yellow);
      }
    }
    
    class Orange
    {
      public static FD GetDescription()
      {
        return new FD(Color.Orange);
      }
    }
    
    void DoStuff(FD fd)
    {
    }
    
    DoStuff(Banana.GetDescription());
    


    • Proposed as answer by Lentucky Monday, August 2, 2010 11:05 PM
    Monday, August 2, 2010 9:18 AM
  • And I'm sure both of you know the color of a Banana without actually see one...

    And I'm sure both of you know the static member for color of a Banana-class without instantiating one.

     

    If you are using the class "Banana" directly, then there isn't any need for inheritance, because, you don't use the abstract fruit, you are using the concrete banana. If you want to use these information in instance AND static, then you have to provide both. I.e. you can override the Fruit-Color-Property and return the constant-class-color.

    Monday, August 2, 2010 9:18 AM
  • Are you using any instance of a Fruit? If not, you could redesign it to have one instance of Fruit for each different kind of fruit instead of multiple classes.

    Monday, August 2, 2010 9:26 AM
  • If Fruit and FruitDescription are in the same project A, and Banana in project B:

    B reference A because Banana inherits from Fruit. A reference B because FruitDescription use Banana: cyclic dependancy :(

     

     

    Edit:

    I should have read your post entirely before answering, sorry!

     

    It's seems to be the best solution for now, I will try to implement something like this, and report back tomorrow

     

    Monday, August 2, 2010 9:26 AM
  • If Fruit and FruitDescription are in the same project A, and Banana in project B:

    B reference A because Banana inherits from Fruit. A reference B because FruitDescription use Banana: cyclic dependancy :(

     


    No FD is defined in A. B is just instantiating the FD.

     

    Maybe that?

        public abstract class fruit
        {
          public enum fruitishColors {unknown,yellow,blue,orange};
          public static fruitishColors color = fruitishColors.unknown;
          public abstract fruitishColors Color { get; }
        }
        public class banana : fruit
        {
          public static new fruitishColors color = fruitishColors.yellow;
          public override fruitishColors Color { get { return color; } }
        }
    
        static void Main(string[] args ) {
          Console.WriteLine(fruit.color);
          Console.WriteLine(banana.color);
          Console.WriteLine(new banana().Color);
    
          Console.ReadLine();
        }
    
    Monday, August 2, 2010 9:30 AM
  • GreatVolk: But of course, the problem is that we don't want to know the color of Banana but the color of T. (Where T is a Fruit.)

     

    FruitDescription doesn't use Banana:

    class FruitDescription
    {
      public FruitDescription(Color color)
      {
        this.Color = color;
      }
    
      public Color Color
      {
        get;
        private set;
      }
    }
    

    Monday, August 2, 2010 9:32 AM
  • GreatVolk: But of course, the problem is that we don't want to know the color of Banana but the color of T. (Where T is a Fruit.)

     

    FruitDescription doesn't use Banana:

     

    class FruitDescription
    
    {
    
     public FruitDescription(Color color)
    
     {
    
      this.Color = color;
    
     }
    
    
    
     public Color Color
    
     {
    
      get;
    
      private set;
    
     }
    
    }
    
    

     


    Makes no difference, because in that case, you need the Banana-class to get the your FruitDescirption, just to Call Banana.GetDescription().

    You can either use the class directly with static fields, or you instantiate the class and use virtual methods. There is no static abstract method. Somehow the programmer must define, what he is talking about. Either by using the class name, or by using the object ot the class.

    Monday, August 2, 2010 9:44 AM
  • GreatVolk, you're missing the point. Bleu wants to use his Fruit classes as generic type parameters.

    (And my last reply to you was actually a reply to "And I'm sure both of you know the static member for color of a Banana-class without instantiating one" ;), we just posted at the same time.)

    Monday, August 2, 2010 9:50 AM
  • Having each Fruit subclass holding a FD instead of holding a Color doesn't change anything: you need to rely on the programmer to always add a GetDescription to each subclass, and you cannot call GetDescription on a type parameter.

    You won't be able to access the color through a type parameter without resorting to reflection. You'd then better include the color directly in the fruit to simplify it.

    Or have FruitDescription know the color of every kind of fruit. Something similar to the Map idea of the OP.

    Monday, August 2, 2010 10:06 AM
  • Here is the solution I finally implemented:

     

    Instead of trying to mix my fruit this way:

    new Mixer<Banana>();
    
     which call the constructor
    Mixer<T>() { /* */ T.color /* */ }
    

     

    I simply added a parameter to the constructor:

    new Mixer<Banana>(Banana.color);
    

    and reference the color of my fruit mix thanks to the argument:

    Mixer<T>(Color color) { /* */ color /* */ }
    

     

    It's no as "beautiful" as I wanted, but at least, I just have to add an argument, not a whole class or a project.

    Tell me I you think there is a better way, and thank you all for your time.

     

     

    Monday, August 2, 2010 4:49 PM
  • I don't really like it because you have to pass both the color and the type. I was hoping that maybe there's a way to split your functions into the ones that need the type parameter and the ones than only need the color. If you need both then maybe adding the map or using reflection would look a bit cleaner.

    EDIT: If you only need the type parameter to instantiate your bananas, you could add that functionality to FD instead:

      class FruitDescriptor
      {
        public abstract Color Color
        {
          get;
        }
    
        public abstract Fruit CreateInstance();
      }
    
      class BananaDescriptor : FruitDescriptor
      {
        public override Color Color
        {
          get { return Color.Yellow; }
        }
    
        public override Fruit CreateInstance()
        {
          return new Banana();
        }
      }
    

    • Marked as answer by Bleubleubleu Tuesday, August 3, 2010 12:09 PM
    Monday, August 2, 2010 10:25 PM
  • I think that your last post can be marked as an answer: the best solution should be to create a new hierarchy level for implementing the const as a standard field.
    Tuesday, August 3, 2010 11:20 AM
  • I think that your last post can be marked as an answer: the best solution should be to create a new hierarchy level for implementing the const as a standard field.


    Can you mark please as anwered, then we can close this thread.

    thanks


    Just Be Humble Malange!
    Tuesday, August 3, 2010 12:06 PM