|
Hi, I would like to initialize a generic using a string.
Type t = Type.GetType("double")
List<t> MyList = new List<t>();
It doesn't work.
Is it possible to do it?
thanks for your time
|
|
|
|
|
List<t> MyList = new List<t>();
Nope. The whole generics stuff is dealt with by the compiler, so the types (such as your t) have to be known at compile time.
|
|
|
|
|
no way of a work around?
I have a string input and need to initialize a generic. It is a big constrain apparently
|
|
|
|
|
You can't get List<T> to compile when T is unknown.
There are things one can do with reflection, they are complex and/or tedious. Maybe you should explain what you really want to achieve, at some higher level.
|
|
|
|
|
I need to initialize a generic class like:
class myClass < T, G > where T: car
where G: moto
{
...
}
car and moto are base classes, with lots of derived classes each. Since I use an excel file to initialize the class myClass I will enter in excel T and G as string from a List (after data validation), and I would like to initialize the correct class. Not easy to use a switch statement since I have more than 20 derived class for T and 15 derived class for G
|
|
|
|
|
That seems like a completely different question. How about this:
1. if you need a specialized car, use a CarFactory method that returns a Car of the correct derived type; you can do this either with a switch, or with reflection; search for the Factory pattern, and Activator.CreateInstance()
2. if you need a collection of them, collect the base type, hence List<Car> ; it will gladly hold any object that is a Car or a Car derivative.
PS: wherever it said base class, you could substitute interface.
|
|
|
|
|
Thank for reply.
2 main problems.
1) myClass uses specialization of car an moto at the same time. The problem is the conjuncted combination of specializations. 20 car and 15 moto... myClass can be inizialized in a lot of combinations.
2) the input is from excel. I should use something that convert string to class. Factory for specialization of car only is ok. But I need combination of specialization..
Thnaks
|
|
|
|
|
- IMoto interface
- ICar interface exposing a Moto property of type IMoto
- Moto factory returning an implementation of IMoto, the concrete implementation determined by switch statement
- car factory returning an implementation of ICar, the concrete implementation determined by switch statement and setting the Moto property using the Moto factory
e.g.
public class CarFactory
{
public ICar CreateCar(string carID, string motoID)
{
ICar result;
switch(carID)
{
case "jaguar":
result = new Jaguar();
break;
case "porche":
result = new porche();
break;
}
result.Moto = MotoFactory.Create(MotoID);
return result;
}
}
public class MotoFactory
{
public IMoto Create(string motoID)
{
IMoto result;
switch(motoID)
{
case "uber":
result = new UberMoto();
break;
case "pants":
result = new PantsMoto();
break;
}
return result;
}
}
Pedis ex oris
Quidquid latine dictum sit, altum sonatur
|
|
|
|
|
Oky, qquestion:
how to use the syntax with a class
myClass<t,g>: where t: car where g: moto
Can not do:
myClass< CarFactory.Create("jaguar"), MotoFactory.Create("uber")> o = new ...
myClas
|
|
|
|
|
aside from
myClass<ICar,IMoto> you can't without some nasty reflection (detailed in other replies)
My question would be why you need to use generics for this.
With the interface driven approach the ICar has an Imoto in a strategy pattern. your myClass could be simply written to work with ICar instances regardless of the concrete types.
this would require the ICar interface to be well designed but since your myClass clas is designed to work with any combination of car and moto then it should be easy to determine the common functionality to place on the ICar and IMoto interfaces
why pass concrete types when a common interface will suffice?
Pedis ex oris
Quidquid latine dictum sit, altum sonatur
|
|
|
|
|
TheGermoz wrote: Not easy to use a switch statement since I have more than 20 derived class for T
and 15 derived class for G
That would suggest a design problem not an initialization problem.
But other than that "easy" sounds like a bit of a crutch. Presumably you just don't want to type all of those. So write a code generator to generate them.
|
|
|
|
|
|
I try to make a more precise example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGeneric
{
class Program
{
static void Main(string[] args)
{
string myKeyType = "string";
string myValueType = "double";
#region From Here I heve problem...
Type d1 = typeof(myClass<,>);
Type[] typeArgs = { typeof(Type.GetType(myKeyType)), typeof(Type.GetType(myValueype)) };
Type constructed = d1.MakeGenericType(typeArgs);
#endregion
}
}
public class myClass<T, G>
{
Dictionary<T, G> mD;
public myClass()
{
mD = new Dictionary<T, G>();
}
}
}
|
|
|
|
|
Still not sure exactly what problem you are having, but here is an example much like yours (I compiled and ran it to confirm it works):
string myKeyType = "System.String";
string myValueType = "System.Double";
Type myType = typeof(KeyValuePair<,>);
Type[] typeArgs = { Type.GetType(myKeyType), Type.GetType(myValueType) };
Type fullType = myType.MakeGenericType(typeArgs);
object newInstance = Activator.CreateInstance(fullType, new object[] { "testKey", 5 });
KeyValuePair<string, double> casted = (KeyValuePair<string, double>)newInstance;
MessageBox.Show(casted.Key + "_" + casted.Value.ToString());
Note that you must use the full type in the strings and it must have the correct casing (uppercase/lowercase). If you are getting "string" and "double", you must first convert them to "System.String" and "System.Double" first. If you wanted, there are also ways to scan an assembly to see all of the possible types it provides, which would allow you to, for example, do a case-insensitive scan for types which contain "double". You could then use that type in your code. However, I wouldn't recommend that... I'd say you should make sure your data is correct (your data in this case being the strings that represent the types).
|
|
|
|
|
Thanks
string myKeyType = "System.String";
string myValueType = "System.Double";
Type myType = typeof(KeyValuePair<,>);
Type[] typeArgs = { Type.GetType(myKeyType), Type.GetType(myValueType) };
Type fullType = myType.MakeGenericType(typeArgs);
object newInstance = Activator.CreateInstance(fullType, new object[] { "testKey", 5 });
It is my first problem: so solved.
But If then I have to use the object I do not want to cast it in the following way
KeyValuePair<string, double> casted = (KeyValuePair<string, double>)newInstance;
Since a priori I do not know the type of course..
object newInstance: how can use it?
|
|
|
|
|
You can use it with Reflection. With Reflection, you can call methods, set property values, pass parameters, and so on. I imagine you can Google what you want to do (e.g., "C# Reflection set property value") and you'll probably get the answer you're looking for. And that link I sent you to my tip/trick shows how to set a property using Reflection.
You could also dynamically construct expression trees and then compile them if you want code that works faster than Reflection, but I'm not as familiar with expression trees so you'd be on your own for that.
|
|
|
|
|
Also, maybe this is one reason you were having a problem:
Type[] typeArgs = { typeof(Type.GetType(myKeyType)), typeof(Type.GetType(myValueype)) };
You don't need to use typeof , as the GetType function returns a type.
|
|
|
|
|
I can almost guarantee that you don't want to do what you think you do. If you create a type via reflection, you can't use it in a normal compile-time way because the type is not known until runtime. That means you need to do everything about it through reflection, which is slow.
I still don't have a good understanding of what exactly you're trying to do, but generally you want to use a List<BaseClass> or List<Interface>, where all the classes you're picking between at runtime inherit from/implement the class/interface in question. Then you can use compile time method binding (i.e. write normal code) against the class/interface, and use the magic of OO (polymorphism) to get different functionality.
In this case it appears you already have the base classes, and in fact you just want the (compile time) class MyClass to be written in terms of Car and Moto. (I hope that MyClass is a dummy name! Make sure your classes have meaningful names.) I'm not even sure you need generics here. Remember that if you have
class MyClass {
void SomeMethod(Car car, Moto moto){ ... }
}
... you can pass any instance of a subclass of Car and/or Moto to it. The same applies if you're using a generic class at some point, for example if your implementation includes a List<Car> – you can still put an AudiA8 into that list, as long as that class inherits from Car, even if the class is loaded at runtime.
I suspect what you actually want is something like
class MyClass {
public Car Car { get; set; }
public Moto Moto { get; set; }
...
}
... and then to set the properties to instances of subclasses of Car and Moto as chosen at runtime.
|
|
|
|
|
not sure I have explained my problem.
I have string and I need to inizialize the class
So from may excel i get "AudiA8", "ZXR"
And I need to inizialize:
MyClass.SomeMethod(AudiA8,ZXR) //from string to class
|
|
|
|
|
You have not explained your problem. And you still haven't.
Here's the part you may not be getting. If AudiA8 is a Car (i.e. it inherits from Car, or implements ICar), then you can pass it to a method taking a car. That is, you can do
MyClass.SomeMethod(new AudiA8(), new ZXR());
... given
class AudiA8 : Car {
...
}
class ZXR : Moto {
...
}
and
class MyClass {
static void SomeMethod(Car car, Moto moto){ ... }
}
You don't need any runtime shenanigans with MyClass to make that work. You can still do this even if you're creating the cars/motos at runtime:
Car CreateCar(string classname){
return (Car)Activator.CreateInstance(classname);
}
Moto CreateMoto(string classname){
return (Moto)Activator.CreateInstance(classname);
}
void DoSomething(){
MyClass.SomeMethod(
CreateCar("YourNamespace.Cars.AudiA8"),
CreateMoto("YourNamespace.Motos.ZXR")
);
}
|
|
|
|
|
MyClass.SomeMethod(new AudiA8(), new ZXR());
... given
class AudiA8 : Car {
...
}
class ZXR : Moto {
...
}
yes but from excel i have a string "AudiA8" and not new AudiA8()
myClass<car, mot>
...generic need car as a type but not as string, but I have only string as input
|
|
|
|
|
Did you bother reading my previous post all the way to the bottom where it shows you how to instantiate a type from a string?
|
|
|
|
|
Yes sorry, I'm not able to fit the solution in my case
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGeneric
{
class Program
{
static void Main(string[] args)
{
string myCar = "carA";
string myMoto = "motoB";
mPricer< (car) Activator.CreateInstance(myCar), (moto) Activator.CreateInstance(myMoto)> Pr = new mPricer< (car) Activator.CreateInstance(myCar), (moto) Activator.CreateInstance(myMoto)>();
}
}
public class mPricer<T, G>
where T:car, new()
where G : moto, new()
{
double total;
public mPricer()
{
T c = new T();
G m = new G();
total = c.GetPrice() + m.GetCost();
}
public void ShowTotal()
{
Console.WriteLine(total);
}
}
public abstract class car { abstract public double GetPrice();}
public class carA : car { public override double GetPrice() { return 11; } }
public class carB : car { public override double GetPrice() { return 12; } }
public abstract class moto { abstract public double GetCost(); }
public class motoA : moto { public override double GetCost() { return 7; } }
public class motoB : moto { public override double GetCost() { return 6; } }
}
modified 15-Feb-12 9:04am.
|
|
|
|
|
There is no reason why mPricer should construct these objects within its own constructor. Construct them outside and pass them in, statically typed as car and moto, as in my example.
// I need to obtain an istance of mPricer<carA,motoB> starting from strings
No, no you do not, and until you understand this you're going to keep tying yourself in knots. You need to obtain an instance of mPricer the car and moto instances of which are instantiated from strings. I already demonstrated how to do this.
You seem to show a fundamental lack of understanding of the difference between types and instances, and frankly until you get a grip on that you shouldn't be dabbling with this sort of runtime creation.
|
|
|
|
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGeneric
{
class Program
{
static void Main(string[] args)
{
string myCar = "carA";
string myMoto = "motoB";
mPricer Pr = new mPricer(myCar,myMoto);
}
}
public class mPricer
{
double total;
public mPricer(string carId, string motoId)
{
Car c = (car) Activator.CreateInstance(myCar);
Moto m = (moto) Activator.CreateInstance(myMoto);
total = c.GetPrice() + m.GetCost();
}
public void ShowTotal()
{
Console.WriteLine(total);
}
}
public abstract class car { abstract public double GetPrice();}
public class carA : car { public override double GetPrice() { return 11; } }
public class carB : car { public override double GetPrice() { return 12; } }
public abstract class moto { abstract public double GetCost(); }
public class motoA : moto { public override double GetCost() { return 7; } }
public class motoB : moto { public override double GetCost() { return 6; } }
}
That, i think, should do it ... you don't need a generic class
Pedis ex oris
Quidquid latine dictum sit, altum sonatur
|
|
|
|