locked
Associating one class with another class RRS feed

  • Question

  • Is embedding Type property inside a class a good way to associate it with another class? (like itself indicating "Hey I belong to that class over there")


    I  have a large setting configuration that defines 5 settings, each for working on 5 different object types

    I was thinking of embedding a Type property inside the settings class that indicates the exact Type of object it refers to

    Like:

    SettingsClass1 : ISettings {

       ...

       public Type ObjectTypeIBelongTo {get {return typeOf(ConcreteObject1); }}

    }

    SettingsClass2 : ISettings {

       ...

       public Type ObjectTypeIBelongTo {get {return typeOf(ConcreteObject2); }}

    }


    Class ConcreteObject1 : IConcreteObject{

    }

    Class ConcreteObject2 : IConcreteObject{

    }

    ...

    And then I was thinking of creating a Dictionary that contains the setting and the typeName it refers to like

    Dictionary<string, ISettings> mappings;

    where string would be the name of the Type ObjectTypeIBelongTo

    So whenever I encountered an IConcreteObject, I can immediately pull the appropriate settings fom the dictionary by doing

    IConcreteObject ConcObj = new ConcreteObject1();

    string concreteObjectName = ConcObj.GetType().Name;

    ISettings setting = mappings[concreteObjectName];

    **The only problem I can see is that my solution only tells you who belongs to who and doesn't really enforce it strongly enough.  Like nothing is preventing the user to match the wrong setting class with the concreteObject class. Although if this is internal structure of an API that is not exposed to end user, would it still be acceptable?

    Tuesday, December 30, 2014 8:50 PM

Answers

  • OK, I had some time after dinner and a movie, so I figured I'd write this up for you real quick. I'm not going to post the DependencyManager class here, that can be found in my blog post.

    protected void TestDependencyManager()
    {
     // Register the settings objects with the appropriate ConcreteObjectX classes
     ISettings settings1 = new Settings1();
     DependencyManager.Current.Register<ConcreteObject1>(settings1);
     // or even like this
     DependencyManager.Current.Register<ConcreteObject2>(new Settings2());
    
     // then later, when you instantiate your concrete objects
     // set the settings like this:
     ConcreteObject1 co1 = new ConcreteObject1();
     co1.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject1>();
    
     // you could also put this directly in the ConcreteObjectX class constructor
     // see ConcreteObject2 below
    }
    protected class ConcreteObject1
    {
     public ISettings settings { get; set; }
    }
    protected class ConcreteObject2
    {
     public ISettings settings { get; set; }
     public ConcreteObject2()
     {
      this.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject2>();
     }
    }
    protected interface ISettings
    {
    }
    protected class Settings1 : ISettings
    {
    }
    protected class Settings2 : ISettings
    {
    }
    


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    • Marked as answer by Kristin Xie Wednesday, January 7, 2015 9:17 AM
    Sunday, January 4, 2015 6:17 AM

All replies

  • When you build a class object the Net library automatically gets an enumeration for the class which can be retrieved using the typeof() method.  The problem with using this enumeration it is a random number that makes it difficult to use when debugging the code.  I like adding a string name to my classes to make the code easier to debug, but like you said the name isn't strongly enforced.  So you can do something like this

    class myClass
        {
            string className;
            protected myClass()
            {
            }
            public myClass(string name)
            {
                className = name;
            }
        }
        class myClassA : myClass
        {
        }
        class myClassB : myClass
        {
        }
        class myClassC : myClass
        {
        }
        class myClassD : myClass
        {
        }


    jdweng

    Tuesday, December 30, 2014 10:08 PM
  • I suggest an alternative design:

    Inside your IConcreteObject interface define a method that returns ISettings:

    ISettings GetSettings();

    Then, each of the ConcreteObject classes will provide a method that returns the specific class that implements the settings for that ConcreteObject. In this way you always enforce the matching between the class and its settings.

    Wednesday, December 31, 2014 6:14 PM
  • I suggest an alternative design:

    Inside your IConcreteObject interface define a method that returns ISettings:

    ISettings GetSettings();

    Then, each of the ConcreteObject classes will provide a method that returns the specific class that implements the settings for that ConcreteObject. In this way you always enforce the matching between the class and its settings.

    This sounds reasonable and also something I would like to do,  However what is happening is that I am loading the settings from my XML file in advance and storing them in the dictionary for easy retrieval.  I don't have the Concrete objects yet because they are coming into my method one at a time for processing.  So they are completely detached from their settings.   (i.e. I am trying to 'inject' the appropriate settings into the concrete objects as they arrive for processing)

    I think in the way you suggest I would have to have created an instance of an IConcreteObject first in order to get the ISettings object, but at time of reading my configuration file I do not have the concrete objects yet.


    • Edited by sjs1978 Wednesday, December 31, 2014 7:29 PM
    Wednesday, December 31, 2014 7:23 PM
  • Deserialize() method will read XML into your defined classes.

    jdweng

    Wednesday, December 31, 2014 8:48 PM
  • Deserialize() method will read XML into your defined classes.

    jdweng

    That's not a problem, I have a custom XML reader writer class (implementing IXmlSerializable) so getting the XML settings into a class is already done.
    Wednesday, December 31, 2014 8:52 PM
  • I'm thinking you need to use some kind of IoC (Inversion of Control). I have a blog post about a very simple IoC that we've used in some of our projects. We call the class DependencyManager:

    http://geek-goddess-bonnie.blogspot.com/2014/10/intro-to-ioc.html

    I don't have time right this minute to write up an example for you (I can do that later tonite, or more likely tomorrow). But, read my post and see if you can follow my off-the-top-of-my-head thinking on this:

    Use the DependencyManager to add each of the 5 Setting objects for each of the 5 Types (ConcreteObject1, ConcreteObject2, etc.). Then the concrete objects can get their settings from the DependencyManager. As I said, I can throw some code at you later if (after reading my blog post and, more specifically looking a the code I've posted there for the DependencyManager) you still don't understand what I'm suggesting.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, January 4, 2015 1:46 AM
  • OK, I had some time after dinner and a movie, so I figured I'd write this up for you real quick. I'm not going to post the DependencyManager class here, that can be found in my blog post.

    protected void TestDependencyManager()
    {
     // Register the settings objects with the appropriate ConcreteObjectX classes
     ISettings settings1 = new Settings1();
     DependencyManager.Current.Register<ConcreteObject1>(settings1);
     // or even like this
     DependencyManager.Current.Register<ConcreteObject2>(new Settings2());
    
     // then later, when you instantiate your concrete objects
     // set the settings like this:
     ConcreteObject1 co1 = new ConcreteObject1();
     co1.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject1>();
    
     // you could also put this directly in the ConcreteObjectX class constructor
     // see ConcreteObject2 below
    }
    protected class ConcreteObject1
    {
     public ISettings settings { get; set; }
    }
    protected class ConcreteObject2
    {
     public ISettings settings { get; set; }
     public ConcreteObject2()
     {
      this.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject2>();
     }
    }
    protected interface ISettings
    {
    }
    protected class Settings1 : ISettings
    {
    }
    protected class Settings2 : ISettings
    {
    }
    


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    • Marked as answer by Kristin Xie Wednesday, January 7, 2015 9:17 AM
    Sunday, January 4, 2015 6:17 AM
  • OK, I had some time after dinner and a movie, so I figured I'd write this up for you real quick. I'm not going to post the DependencyManager class here, that can be found in my blog post.

    protected void TestDependencyManager()
    {
     // Register the settings objects with the appropriate ConcreteObjectX classes
     ISettings settings1 = new Settings1();
     DependencyManager.Current.Register<ConcreteObject1>(settings1);
     // or even like this
     DependencyManager.Current.Register<ConcreteObject2>(new Settings2());
    
     // then later, when you instantiate your concrete objects
     // set the settings like this:
     ConcreteObject1 co1 = new ConcreteObject1();
     co1.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject1>();
    
     // you could also put this directly in the ConcreteObjectX class constructor
     // see ConcreteObject2 below
    }
    protected class ConcreteObject1
    {
     public ISettings settings { get; set; }
    }
    protected class ConcreteObject2
    {
     public ISettings settings { get; set; }
     public ConcreteObject2()
     {
      this.settings = (ISettings)DependencyManager.Current.Resolve<ConcreteObject2>();
     }
    }
    protected interface ISettings
    {
    }
    protected class Settings1 : ISettings
    {
    }
    protected class Settings2 : ISettings
    {
    }


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Hi Bonnie, thank you for pointing me to your DepdendancyManager class.  I will give it a try
    Wednesday, January 7, 2015 3:26 PM
  • Let me know if my DependencyManager suggestion works the way you need it to ...

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Friday, January 9, 2015 3:16 PM