Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. .NET (Core and Framework)
  4. Generic class with reference to another generic class

Generic class with reference to another generic class

Scheduled Pinned Locked Moved .NET (Core and Framework)
csharphelpquestion
12 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L lukeer

    Hello experts, how is it possible to create a class with a "tag" of any type that is still type-safe at runtime? That's what generics are for, I suppose. Instances of that class need to have a reference to another instance of that class. But then, the referenced instance should be allowed to host a tag of different type than the referencing instance. I tried to build that in C#:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace Test_Foo
    {
    public class Foo
    {
    public T Tag;

        // \*\*  Declaration  \*\*
        //public Foo \_innerFoo;
        public Foo \_innerFoo;
        // \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
    }
    
    
    public class Bar
    {
        public void Baz()
        {
            Foo intFoo = new Foo();
            intFoo.Tag = 5;
    
            // Causes an error
            intFoo.\_innerFoo = new Foo();
            intFoo.\_innerFoo.Tag = 1.25D;
        }
    }
    

    }

    The marked declaration is where the linked class should go. What would possibly go between < and >? The line marked as error-causing causes an error due to double not being implicitly convertible to int. This, I don't want to do anyway. I do want to have a double there. How can the inner instance have a differently-typed tag than the outer one?

    Ciao, luker

    D Offline
    D Offline
    Dave Kreskowiak
    wrote on last edited by
    #3

    Interesting little problem. You can't do it the way you've written because once you declare what T is (an int), the same T is used throughout the entire class. AFAICT, InnerFoo would have to be declared as a seperate class using it's own type place holder. Something like this:

    public class Foo
    {
    public T Tag;
    public InnerFoo _innerFoo;

        public class InnerFoo
        {
            public S Tag;
        }
    }
    
    
    class Program
    {
        static void Main(string\[\] args)
        {
            Foo intFoo = new Foo();
            intFoo.Tag = 5;
    
            intFoo.\_innerFoo = new Foo.InnerFoo();
            intFoo.\_innerFoo.Tag = 1.25D;
        }
    }
    

    A guide to posting questions on CodeProject[^]
    Dave Kreskowiak

    L 1 Reply Last reply
    0
    • L lukeer

      Hello experts, how is it possible to create a class with a "tag" of any type that is still type-safe at runtime? That's what generics are for, I suppose. Instances of that class need to have a reference to another instance of that class. But then, the referenced instance should be allowed to host a tag of different type than the referencing instance. I tried to build that in C#:

      using System;
      using System.Collections.Generic;
      using System.Text;

      namespace Test_Foo
      {
      public class Foo
      {
      public T Tag;

          // \*\*  Declaration  \*\*
          //public Foo \_innerFoo;
          public Foo \_innerFoo;
          // \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
      }
      
      
      public class Bar
      {
          public void Baz()
          {
              Foo intFoo = new Foo();
              intFoo.Tag = 5;
      
              // Causes an error
              intFoo.\_innerFoo = new Foo();
              intFoo.\_innerFoo.Tag = 1.25D;
          }
      }
      

      }

      The marked declaration is where the linked class should go. What would possibly go between < and >? The line marked as error-causing causes an error due to double not being implicitly convertible to int. This, I don't want to do anyway. I do want to have a double there. How can the inner instance have a differently-typed tag than the outer one?

      Ciao, luker

      P Offline
      P Offline
      Pete OHanlon
      wrote on last edited by
      #4

      Inherently you can't use generics like this. As you are aware, the class is strongly-typed, so _innerFoo is bound to the type of the class, so sorry but there is no way to do this.

      I'm not a stalker, I just know things. Oh by the way, you're out of milk.

      Forgive your enemies - it messes with their heads

      My blog | My articles | MoXAML PowerToys | Onyx

      1 Reply Last reply
      0
      • L lukeer

        Hello experts, how is it possible to create a class with a "tag" of any type that is still type-safe at runtime? That's what generics are for, I suppose. Instances of that class need to have a reference to another instance of that class. But then, the referenced instance should be allowed to host a tag of different type than the referencing instance. I tried to build that in C#:

        using System;
        using System.Collections.Generic;
        using System.Text;

        namespace Test_Foo
        {
        public class Foo
        {
        public T Tag;

            // \*\*  Declaration  \*\*
            //public Foo \_innerFoo;
            public Foo \_innerFoo;
            // \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
        }
        
        
        public class Bar
        {
            public void Baz()
            {
                Foo intFoo = new Foo();
                intFoo.Tag = 5;
        
                // Causes an error
                intFoo.\_innerFoo = new Foo();
                intFoo.\_innerFoo.Tag = 1.25D;
            }
        }
        

        }

        The marked declaration is where the linked class should go. What would possibly go between < and >? The line marked as error-causing causes an error due to double not being implicitly convertible to int. This, I don't want to do anyway. I do want to have a double there. How can the inner instance have a differently-typed tag than the outer one?

        Ciao, luker

        L Offline
        L Offline
        Luc Pattyn
        wrote on last edited by
        #5

        Hi, this seems to do what you want, somewhat:

        namespace Test\_Foo {
        	public class Foo {
        		public T Tag;
        
        		public Foo \_innerFoo;
        	}
        
        
        	public class Bar {
        		public void Baz() {
        			Foo intFoo = new Foo();
        			intFoo.Tag = 5;
        
        			intFoo.\_innerFoo = new Foo();  // <<< second double is arbitrary
        			intFoo.\_innerFoo.Tag = 1.25D;
        		}
        	}
        }
        

        However I don't know what purpose nesting those Foo's would serve as the inner Foo has its own inner Foo, etc. My approach only works well for a nesting depth of 2, if your inner inner foo needs yet another type, you need to add another type parameter, etc. :)

        Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum

        Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.

        L 1 Reply Last reply
        0
        • D Dave Kreskowiak

          Interesting little problem. You can't do it the way you've written because once you declare what T is (an int), the same T is used throughout the entire class. AFAICT, InnerFoo would have to be declared as a seperate class using it's own type place holder. Something like this:

          public class Foo
          {
          public T Tag;
          public InnerFoo _innerFoo;

              public class InnerFoo
              {
                  public S Tag;
              }
          }
          
          
          class Program
          {
              static void Main(string\[\] args)
              {
                  Foo intFoo = new Foo();
                  intFoo.Tag = 5;
          
                  intFoo.\_innerFoo = new Foo.InnerFoo();
                  intFoo.\_innerFoo.Tag = 1.25D;
              }
          }
          

          A guide to posting questions on CodeProject[^]
          Dave Kreskowiak

          L Offline
          L Offline
          lukeer
          wrote on last edited by
          #6

          public class Foo
          {
          public T Tag;

          public class InnerFoo : Foo
          {
          }
          
          /\* mark \*/ public InnerFoo \_innerFoo;
          

          }

          Declaration of the InnerFoo class with its own tag type S seems to work. But declaration of _innerFoo (marked line) fails due to S being not known yet. Declaring _innerFoo without a type parameter doesn't work either. Is there another way to declare _innerFoo without knowing what type it is going to encapsulate?

          Ciao, luker

          D 1 Reply Last reply
          0
          • L Luc Pattyn

            Hi, this seems to do what you want, somewhat:

            namespace Test\_Foo {
            	public class Foo {
            		public T Tag;
            
            		public Foo \_innerFoo;
            	}
            
            
            	public class Bar {
            		public void Baz() {
            			Foo intFoo = new Foo();
            			intFoo.Tag = 5;
            
            			intFoo.\_innerFoo = new Foo();  // <<< second double is arbitrary
            			intFoo.\_innerFoo.Tag = 1.25D;
            		}
            	}
            }
            

            However I don't know what purpose nesting those Foo's would serve as the inner Foo has its own inner Foo, etc. My approach only works well for a nesting depth of 2, if your inner inner foo needs yet another type, you need to add another type parameter, etc. :)

            Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum

            Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.

            L Offline
            L Offline
            lukeer
            wrote on last edited by
            #7

            Since the nesting depth is potentially limited only by available memory, and the sequence of tag types, if used this way, would have to be known at declaration time of the outermost foo, this approach seems not suitable yet. For the purpose of nesting Foo's: It's an attempt to merge method return value and possible error handling without the performance impact of exception handling in case of an error. And I personally don't like out-parameters too much.

            Ciao, luker

            N 1 Reply Last reply
            0
            • L lukeer

              public class Foo
              {
              public T Tag;

              public class InnerFoo : Foo
              {
              }
              
              /\* mark \*/ public InnerFoo \_innerFoo;
              

              }

              Declaration of the InnerFoo class with its own tag type S seems to work. But declaration of _innerFoo (marked line) fails due to S being not known yet. Declaring _innerFoo without a type parameter doesn't work either. Is there another way to declare _innerFoo without knowing what type it is going to encapsulate?

              Ciao, luker

              D Offline
              D Offline
              Dave Kreskowiak
              wrote on last edited by
              #8

              I tried that code on .NET 4.0 and it worked perfectly. Since this method can only go one level deep, it's not going to work for you anyway. Off the top of my head, the only other way I can find that would allow this removes all type checking on InnerFoo and introduces a performance penalty. That would be to declare InnerFoo As Object. It appears as though you're putting together a chain of values of different types. You might want to look into a LinkedList to see if that helps.

              A guide to posting questions on CodeProject[^]
              Dave Kreskowiak

              L 1 Reply Last reply
              0
              • D Dave Kreskowiak

                I tried that code on .NET 4.0 and it worked perfectly. Since this method can only go one level deep, it's not going to work for you anyway. Off the top of my head, the only other way I can find that would allow this removes all type checking on InnerFoo and introduces a performance penalty. That would be to declare InnerFoo As Object. It appears as though you're putting together a chain of values of different types. You might want to look into a LinkedList to see if that helps.

                A guide to posting questions on CodeProject[^]
                Dave Kreskowiak

                L Offline
                L Offline
                lukeer
                wrote on last edited by
                #9

                Maybe it's a limitation of .NET 2.0, which I use. From what I read, it's the latest .NET version running on Windows 2000, which is mandatory for this project. But the two-level limit should not be a problem for this design. Since InnerFoo is derived from Foo, it again should contain an inner foo class of different tag type. Removing all type checking would equal my current design using object as tag type. The linking is just one aspect of this class. LinkedList therefore doesn't serve its other needs. However, I'm going to try the .NET 4.0 approach. Thanks for the hint. Ciao, luker

                D 1 Reply Last reply
                0
                • L lukeer

                  Maybe it's a limitation of .NET 2.0, which I use. From what I read, it's the latest .NET version running on Windows 2000, which is mandatory for this project. But the two-level limit should not be a problem for this design. Since InnerFoo is derived from Foo, it again should contain an inner foo class of different tag type. Removing all type checking would equal my current design using object as tag type. The linking is just one aspect of this class. LinkedList therefore doesn't serve its other needs. However, I'm going to try the .NET 4.0 approach. Thanks for the hint. Ciao, luker

                  D Offline
                  D Offline
                  Dave Kreskowiak
                  wrote on last edited by
                  #10

                  My bad - it doesn't work. I went back and replicated this and found that I did something wrong and it gave me the illusion that it worked! I can't get this to work using Generics, but it does work like this:

                  namespace ClassLibrary1
                  {
                  public class Foo
                  {
                  public Type valueType;
                  public Object Tag;

                      public Foo innerFoo;
                  }
                  
                  class Program
                  {
                      static void Main(string\[\] args)
                      {
                          Foo intFoo = new Foo();
                          intFoo.valueType = typeof(int);
                          intFoo.Tag = 5;
                  
                          intFoo.innerFoo = new Foo();
                          intFoo.innerFoo.valueType = typeof(double);
                          intFoo.innerFoo.Tag = 1.25D;
                      }
                  }
                  

                  }

                  Obviously, since Object is being used to store any type, there is a performance penalty to unbox the type and get the correct value.

                  A guide to posting questions on CodeProject[^]
                  Dave Kreskowiak

                  1 Reply Last reply
                  0
                  • L lukeer

                    Since the nesting depth is potentially limited only by available memory, and the sequence of tag types, if used this way, would have to be known at declaration time of the outermost foo, this approach seems not suitable yet. For the purpose of nesting Foo's: It's an attempt to merge method return value and possible error handling without the performance impact of exception handling in case of an error. And I personally don't like out-parameters too much.

                    Ciao, luker

                    N Offline
                    N Offline
                    Nitin Singh India
                    wrote on last edited by
                    #11

                    Even if technically possible, what's the logical need of accomplishing it? Generics do allow specific types to be used, but this need is more like having a tree with each branch capable of bearing a different fruit :doh:

                    Code can solve a problem identified; but first identify the problem itself

                    L 1 Reply Last reply
                    0
                    • N Nitin Singh India

                      Even if technically possible, what's the logical need of accomplishing it? Generics do allow specific types to be used, but this need is more like having a tree with each branch capable of bearing a different fruit :doh:

                      Code can solve a problem identified; but first identify the problem itself

                      L Offline
                      L Offline
                      lukeer
                      wrote on last edited by
                      #12

                      As I said in the post you repied to, it's to combine result value and error handling. The tree you mention is a good analogy to what I'm trying to create: there is a task to do with several sub-tasks which themselves have sub-sub-tasks. Each of those could fail and therefore return an error. Each could as well return some result just as expected. The tree structure is built of error messages, including "There was no error. Everything went fine". Besides the error, especially in those "Everything fine" cases, there shall return a result value. It is of type object at the moment. I would like to have it type-safe. Therefore the need to tell the error object what type the nested return value should have. Ciao, luker

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups