Generic class with reference to another generic class
-
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
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 -
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
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
-
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
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.
-
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 Kreskowiakpublic class Foo
{
public T Tag;public class InnerFoo : Foo { } /\* mark \*/ public InnerFoo \_innerFoo;
}
Declaration of the
InnerFoo
class with its own tag typeS
seems to work. But declaration of_innerFoo
(marked line) fails due toS
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
-
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.
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
-
public class Foo
{
public T Tag;public class InnerFoo : Foo { } /\* mark \*/ public InnerFoo \_innerFoo;
}
Declaration of the
InnerFoo
class with its own tag typeS
seems to work. But declaration of_innerFoo
(marked line) fails due toS
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
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 -
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 KreskowiakMaybe 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
-
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
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 -
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
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
-
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
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