How to instantiate an object with a generic parameter?
-
Hello, I can't figure this one out, so I'll be happy if someone lends me a helping hand here. How do I instantiate an object with a generic type parameter if I don't know what the type parameter will be at run time? Example:
namespace GenericTypeInitialization
{
class Program
{
static void Main()
{
Console.WriteLine("Press 1 for FooA, press 2 for FooB:");
ConsoleKeyInfo key = Console.ReadKey(true);Type TypeOfFoo; if (key.KeyChar == '1') { Console.WriteLine("FooA selected."); TypeOfFoo = typeof(FooA); } else if (key.KeyChar == '2') { Console.WriteLine("FooB selected."); TypeOfFoo = typeof(FooB); } //// Bar<TypeOfFoo> MyInstanceOfBar = new Bar<TypeOfFoo>(); } } class FooA {} class FooB {} class Bar<TFoo> {}
}
Obviously, the above code doesn't compile. I'm getting an error of The type or namespace name 'TypeOfFoo' could not be found (are you missing a using directive or an assembly reference?) How do I get the type parameter at run time then? I've tried various things, but none worked. Also, you can't instantiate the Bar<> class before '////'. Thanks a lot for any input, Michal
You can't. Generics in .NET are evaluated during runtime creating special types, [^] The best solution to your problem is to use inheritance and base classes.
Need a C# Consultant? I'm available.
Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway -
Hello, I can't figure this one out, so I'll be happy if someone lends me a helping hand here. How do I instantiate an object with a generic type parameter if I don't know what the type parameter will be at run time? Example:
namespace GenericTypeInitialization
{
class Program
{
static void Main()
{
Console.WriteLine("Press 1 for FooA, press 2 for FooB:");
ConsoleKeyInfo key = Console.ReadKey(true);Type TypeOfFoo; if (key.KeyChar == '1') { Console.WriteLine("FooA selected."); TypeOfFoo = typeof(FooA); } else if (key.KeyChar == '2') { Console.WriteLine("FooB selected."); TypeOfFoo = typeof(FooB); } //// Bar<TypeOfFoo> MyInstanceOfBar = new Bar<TypeOfFoo>(); } } class FooA {} class FooB {} class Bar<TFoo> {}
}
Obviously, the above code doesn't compile. I'm getting an error of The type or namespace name 'TypeOfFoo' could not be found (are you missing a using directive or an assembly reference?) How do I get the type parameter at run time then? I've tried various things, but none worked. Also, you can't instantiate the Bar<> class before '////'. Thanks a lot for any input, Michal
Generics are designed to be used when you know the type at compile-time (early binding). When you don't know the type until run-time (late binding), you have to use reflection.
----- You seem eager to impose your preference of preventing others from imposing their preferences on others. -- Red Stateler, Master of Circular Reasoning and other fallacies If atheism is a religion, then not collecting stamps is a hobby. -- Unknown God is the only being who, to rule, does not need to exist. -- Charles Baudelaire
-
Generics are designed to be used when you know the type at compile-time (early binding). When you don't know the type until run-time (late binding), you have to use reflection.
----- You seem eager to impose your preference of preventing others from imposing their preferences on others. -- Red Stateler, Master of Circular Reasoning and other fallacies If atheism is a religion, then not collecting stamps is a hobby. -- Unknown God is the only being who, to rule, does not need to exist. -- Charles Baudelaire
Ok, so how would you use reflection to make the above example work as intended? Thanks, Michal
-
Ok, so how would you use reflection to make the above example work as intended? Thanks, Michal
I reexamined your example, and her is what I suggest. Since you only have 2 well-known concrete classes, you may not need reflection for now, but generics is not the way to go either. Make an interface:
public interface IFoo { void MyMethod(); // Interface defines one method. }
Then have some implementation, 2 in you example:
public class FooA : IFoo { public void MyMethod() { Console.WriteLine("Hello from FooA"); } } public class FooB : IFoo { public void MyMethod() { Console.WriteLine("Hello from FooB"); } }
Then, using your example code:
class Program { static void Main() { Console.WriteLine("Press 1 for FooA, press 2 for FooB:"); ConsoleKeyInfo key = Console.ReadKey(true); IFoo myFoo = null; if (key.KeyChar == '1') { myFoo = new FooA(); } else if (key.KeyChar == '2') { myFoo = new FooB(); } else { throw new InvalidOperationException("Wrong selection, you must select 1 or 2"); // Always have a watch dog. } myFoo.MyMethod(); // This prints which foo was created. } }
This example is pretty simplistic, but you get the idea. In this particular case, you didn't need generics nor reflection. In real-life application, this is rarely sufficient. Read on reflection, I am sure there are quite good articles on this site. Good luck.
----- You seem eager to impose your preference of preventing others from imposing their preferences on others. -- Red Stateler, Master of Circular Reasoning and other fallacies If atheism is a religion, then not collecting stamps is a hobby. -- Unknown God is the only being who, to rule, does not need to exist. -- Charles Baudelaire
-
I reexamined your example, and her is what I suggest. Since you only have 2 well-known concrete classes, you may not need reflection for now, but generics is not the way to go either. Make an interface:
public interface IFoo { void MyMethod(); // Interface defines one method. }
Then have some implementation, 2 in you example:
public class FooA : IFoo { public void MyMethod() { Console.WriteLine("Hello from FooA"); } } public class FooB : IFoo { public void MyMethod() { Console.WriteLine("Hello from FooB"); } }
Then, using your example code:
class Program { static void Main() { Console.WriteLine("Press 1 for FooA, press 2 for FooB:"); ConsoleKeyInfo key = Console.ReadKey(true); IFoo myFoo = null; if (key.KeyChar == '1') { myFoo = new FooA(); } else if (key.KeyChar == '2') { myFoo = new FooB(); } else { throw new InvalidOperationException("Wrong selection, you must select 1 or 2"); // Always have a watch dog. } myFoo.MyMethod(); // This prints which foo was created. } }
This example is pretty simplistic, but you get the idea. In this particular case, you didn't need generics nor reflection. In real-life application, this is rarely sufficient. Read on reflection, I am sure there are quite good articles on this site. Good luck.
----- You seem eager to impose your preference of preventing others from imposing their preferences on others. -- Red Stateler, Master of Circular Reasoning and other fallacies If atheism is a religion, then not collecting stamps is a hobby. -- Unknown God is the only being who, to rule, does not need to exist. -- Charles Baudelaire
Hello, thanks for your reply. Unfortunately, this is not what I need. Interface was my first thought on how to solve this, but I can't use the interface because I have to be able to copy the containing type by value, not by reference. If you declare the object as an interface, you can only copy it as a reference later on (unless you unbox it in which case you - again - need to know its type :) I did not include the error handling in my example as I guess we are solving something else here. Also, as I said, the type should not be instantiated before '////' mark. It's actually being instantiated much later on in the code, but I need to know the type first. I've been working with reflection and generics before. My above example is a much simplified illustration of what I need to do, but the main issue is still finding out the type and passing it along as a parameter. Thanks, Michal
-
Hello, I can't figure this one out, so I'll be happy if someone lends me a helping hand here. How do I instantiate an object with a generic type parameter if I don't know what the type parameter will be at run time? Example:
namespace GenericTypeInitialization
{
class Program
{
static void Main()
{
Console.WriteLine("Press 1 for FooA, press 2 for FooB:");
ConsoleKeyInfo key = Console.ReadKey(true);Type TypeOfFoo; if (key.KeyChar == '1') { Console.WriteLine("FooA selected."); TypeOfFoo = typeof(FooA); } else if (key.KeyChar == '2') { Console.WriteLine("FooB selected."); TypeOfFoo = typeof(FooB); } //// Bar<TypeOfFoo> MyInstanceOfBar = new Bar<TypeOfFoo>(); } } class FooA {} class FooB {} class Bar<TFoo> {}
}
Obviously, the above code doesn't compile. I'm getting an error of The type or namespace name 'TypeOfFoo' could not be found (are you missing a using directive or an assembly reference?) How do I get the type parameter at run time then? I've tried various things, but none worked. Also, you can't instantiate the Bar<> class before '////'. Thanks a lot for any input, Michal
class Program { static void Main(string[] args) { Console.WriteLine((new Bar<FooA>()).ToString()); Console.WriteLine((new Bar<FooB>()).ToString()); } } public abstract class BaseFoo { } public class FooA: BaseFoo { public FooA() { } public override string ToString() { return "FooA"; } } public class FooB: BaseFoo { public FooB() { } public override string ToString() { return "FooB"; } } public class Bar<TFoo> where TFoo : BaseFoo, new() { TFoo tFoo = new TFoo(); public override string ToString() { return tFoo.ToString(); } }
-
Hello, I can't figure this one out, so I'll be happy if someone lends me a helping hand here. How do I instantiate an object with a generic type parameter if I don't know what the type parameter will be at run time? Example:
namespace GenericTypeInitialization
{
class Program
{
static void Main()
{
Console.WriteLine("Press 1 for FooA, press 2 for FooB:");
ConsoleKeyInfo key = Console.ReadKey(true);Type TypeOfFoo; if (key.KeyChar == '1') { Console.WriteLine("FooA selected."); TypeOfFoo = typeof(FooA); } else if (key.KeyChar == '2') { Console.WriteLine("FooB selected."); TypeOfFoo = typeof(FooB); } //// Bar<TypeOfFoo> MyInstanceOfBar = new Bar<TypeOfFoo>(); } } class FooA {} class FooB {} class Bar<TFoo> {}
}
Obviously, the above code doesn't compile. I'm getting an error of The type or namespace name 'TypeOfFoo' could not be found (are you missing a using directive or an assembly reference?) How do I get the type parameter at run time then? I've tried various things, but none worked. Also, you can't instantiate the Bar<> class before '////'. Thanks a lot for any input, Michal
You'll be looking at TypeBuilder.MakeGenericType unfortunately I think...
Mark Churchill Director Dunn & Churchill Free Download:
Diamond Binding: The simple, powerful, reliable, and effective data layer toolkit for Visual Studio. -
class Program { static void Main(string[] args) { Console.WriteLine((new Bar<FooA>()).ToString()); Console.WriteLine((new Bar<FooB>()).ToString()); } } public abstract class BaseFoo { } public class FooA: BaseFoo { public FooA() { } public override string ToString() { return "FooA"; } } public class FooB: BaseFoo { public FooB() { } public override string ToString() { return "FooB"; } } public class Bar<TFoo> where TFoo : BaseFoo, new() { TFoo tFoo = new TFoo(); public override string ToString() { return tFoo.ToString(); } }
Thanks for your post, but it doesn't solve the problem of instantiating the class with a generic parameter on demand during run time. Also, the generic object can't inherit the abstract class because as I said, it has to be copiable by value, not by reference. Michal
-
You'll be looking at TypeBuilder.MakeGenericType unfortunately I think...
Mark Churchill Director Dunn & Churchill Free Download:
Diamond Binding: The simple, powerful, reliable, and effective data layer toolkit for Visual Studio.Hello, Mark, thanks, I've looked into TypeBuilder, but this class is used to build the objects on the fly. I don't need to BUILD the obect on the fly, I already have the objects well defined beforehand. I just need a reference for that object type. So it looks like this cannot be accomplished in C#.
-
Hello, Mark, thanks, I've looked into TypeBuilder, but this class is used to build the objects on the fly. I don't need to BUILD the obect on the fly, I already have the objects well defined beforehand. I just need a reference for that object type. So it looks like this cannot be accomplished in C#.
You could have an IDictionary and preinitialize it with {typeof(Foo), typeof(Bar< Foo >)}, {typeof(Deh), typeof(Bar< Deh >)...}
Mark Churchill Director Dunn & Churchill Free Download:
Diamond Binding: The simple, powerful, reliable, and effective data layer toolkit for Visual Studio.modified on Thursday, February 07, 2008 6:13:04 AM