Generic parameter/reflection problem
-
Hi, I've created the following function (it gets forms from a pool):
public formType GetForm<formType>(string form_id) where formType : Form
I've stored the type of form I want to get in a Type variable somewhere, for example:Type classToGet = typeof(Form);
TheForm
is just an example, this normally determined dynamically. Now when I try to call my GetForm function like this:GetForm<classToGet>("myformid");
I get a compiler exception saying "classToGet is a type parameter but is used like variable" and that "Type or namespace classToGet could not be found". Is there anyway of solving this problem? I suppose there's a problem involving me not understanding reflection thoroughly enough. I realize I'm passing an argument of typeType
but I can't seem te get my mind around converting theType
class to the class-reference I need here. Thanks in advance for any help!Standards are great! Everybody should have one!
-
Hi, I've created the following function (it gets forms from a pool):
public formType GetForm<formType>(string form_id) where formType : Form
I've stored the type of form I want to get in a Type variable somewhere, for example:Type classToGet = typeof(Form);
TheForm
is just an example, this normally determined dynamically. Now when I try to call my GetForm function like this:GetForm<classToGet>("myformid");
I get a compiler exception saying "classToGet is a type parameter but is used like variable" and that "Type or namespace classToGet could not be found". Is there anyway of solving this problem? I suppose there's a problem involving me not understanding reflection thoroughly enough. I realize I'm passing an argument of typeType
but I can't seem te get my mind around converting theType
class to the class-reference I need here. Thanks in advance for any help!Standards are great! Everybody should have one!
This behaviour is because you are trying to use a variable instead of a type. This goes against the nature of generics which identifies information about an object at compile time. Now, to get around this you would use:
GetForm<Form>("myformid");
Please visit http://www.readytogiveup.com/ and do something special today. Deja View - the feeling that you've seen this post before.
-
Hi, I've created the following function (it gets forms from a pool):
public formType GetForm<formType>(string form_id) where formType : Form
I've stored the type of form I want to get in a Type variable somewhere, for example:Type classToGet = typeof(Form);
TheForm
is just an example, this normally determined dynamically. Now when I try to call my GetForm function like this:GetForm<classToGet>("myformid");
I get a compiler exception saying "classToGet is a type parameter but is used like variable" and that "Type or namespace classToGet could not be found". Is there anyway of solving this problem? I suppose there's a problem involving me not understanding reflection thoroughly enough. I realize I'm passing an argument of typeType
but I can't seem te get my mind around converting theType
class to the class-reference I need here. Thanks in advance for any help!Standards are great! Everybody should have one!
Biggest mistake : this code : Type classToGet = typeof(Form); here Form is the base class of all the forms, so u cant use base class to get the type of form. Instead if u use as argument in typeof() any derived class of base class(Form)then it will return that derived Class and base on it this code : Type classToGet = typeof(DerivedClassOfForm);//Return Form "derived Class" which you can during debug time it will view as GetForm("myformId") GetForm("myformid"); This is difficult to explain as well as to understand :confused:.For more details learn Factory Pattern from http://www.c-sharpcorner.com.:rose:
Regards Chintan www.visharadsoft.com (Nothing is so purify as KNOWLEDGE)
-
This behaviour is because you are trying to use a variable instead of a type. This goes against the nature of generics which identifies information about an object at compile time. Now, to get around this you would use:
GetForm<Form>("myformid");
Please visit http://www.readytogiveup.com/ and do something special today. Deja View - the feeling that you've seen this post before.
I know how to get around it. The thing is, I want to provide the type at runtime using reflection. The reason for this is that somewhere in the GetForm method there's a line saying:
formType ret = Activator.CreateInstance();
I need to call the specific constructor for the type that's provided. This is why simply passing typeForm
will not do. Since I can ensure the compiler that the type passed will be a descendant of Form, I figured there's enough information for it to work with.Standards are great! Everybody should have one!
-
Biggest mistake : this code : Type classToGet = typeof(Form); here Form is the base class of all the forms, so u cant use base class to get the type of form. Instead if u use as argument in typeof() any derived class of base class(Form)then it will return that derived Class and base on it this code : Type classToGet = typeof(DerivedClassOfForm);//Return Form "derived Class" which you can during debug time it will view as GetForm("myformId") GetForm("myformid"); This is difficult to explain as well as to understand :confused:.For more details learn Factory Pattern from http://www.c-sharpcorner.com.:rose:
Regards Chintan www.visharadsoft.com (Nothing is so purify as KNOWLEDGE)
Actually it doesn't work with Form-derived classes either: The Form class was really just an example: At runtime it can be any class implementing Form. Thank you anyway, I'll try and see what I can find at c sharp corner too.
Standards are great! Everybody should have one!
-
I know how to get around it. The thing is, I want to provide the type at runtime using reflection. The reason for this is that somewhere in the GetForm method there's a line saying:
formType ret = Activator.CreateInstance();
I need to call the specific constructor for the type that's provided. This is why simply passing typeForm
will not do. Since I can ensure the compiler that the type passed will be a descendant of Form, I figured there's enough information for it to work with.Standards are great! Everybody should have one!
I don't understand why you would want to do this in this way. As I stated before, generics are really handled at compile time. I knocked up the following quick routine to get a form.
namespace GenericForms { public static class TestForms { public static Form ShowForm(string formName) { return (Form)Activator.CreateInstance(Type.GetType(formName)); } } }
Calling this becomes as simple as
GenericForms.TestForms.ShowForm("Form1").ShowDialog();
.Please visit http://www.readytogiveup.com/ and do something special today. Deja View - the feeling that you've seen this post before.
-
Actually it doesn't work with Form-derived classes either: The Form class was really just an example: At runtime it can be any class implementing Form. Thank you anyway, I'll try and see what I can find at c sharp corner too.
Standards are great! Everybody should have one!
Generics are for compile-time type resolution. For run-time types, use abstract classes or interfaces.
----- If atheism is a religion, then not collecting stamps is a hobby. -- Unknown
-
I don't understand why you would want to do this in this way. As I stated before, generics are really handled at compile time. I knocked up the following quick routine to get a form.
namespace GenericForms { public static class TestForms { public static Form ShowForm(string formName) { return (Form)Activator.CreateInstance(Type.GetType(formName)); } } }
Calling this becomes as simple as
GenericForms.TestForms.ShowForm("Form1").ShowDialog();
.Please visit http://www.readytogiveup.com/ and do something special today. Deja View - the feeling that you've seen this post before.
The thing is, I'm working in a MDI application and want to store and retrieve all of the forms that were open when the application last closed. Here's my code, maybe not so pretty, but I think you'll get it... using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Drawing; using System.Diagnostics; namespace Tools { [Serializable] public class FormsPool { /// /// This dictionary will store the form's properties that we want to save to file. /// private Dictionary dataPool = new Dictionary(); /// /// And this one is used to store forms at runtime. /// [field: NonSerialized] private Dictionary formPool = new Dictionary(); /// /// Get the form with the specified id. /// /// Unique string identifying the form to get. /// public Form GetForm(string form_id) { return GetForm
(form_id); } /// /// Returns the form with the given id from the pool. If it's not there, it'll be constructed. /// /// The form class you want to be returned. /// The id for the form to return. /// public formType GetForm(string form_id) where formType : Form { if (formPool == null) // make sure our dictionaries are there formPool = new Dictionary(); // (deserialization can set them to be null) if (dataPool == null) dataPool = new Dictionary(); if (this.formPool.ContainsKey(form_id)) // check out if we have a reference to the form { if (formPool[form_id] != null) return formPool[form_id] as formType; // if so, return it else formPool.Remove(form_id); } formType ret = Activator.CreateInstance(); // not there, so create it if (dataPool.ContainsKey(form_id)) //
-
Hi, I've created the following function (it gets forms from a pool):
public formType GetForm<formType>(string form_id) where formType : Form
I've stored the type of form I want to get in a Type variable somewhere, for example:Type classToGet = typeof(Form);
TheForm
is just an example, this normally determined dynamically. Now when I try to call my GetForm function like this:GetForm<classToGet>("myformid");
I get a compiler exception saying "classToGet is a type parameter but is used like variable" and that "Type or namespace classToGet could not be found". Is there anyway of solving this problem? I suppose there's a problem involving me not understanding reflection thoroughly enough. I realize I'm passing an argument of typeType
but I can't seem te get my mind around converting theType
class to the class-reference I need here. Thanks in advance for any help!Standards are great! Everybody should have one!
Dictionary pool = new Dictionary(10); pool.Add("myformid", new LoginForm()); pool.Add("myAboutformid", new AboutForm()); public class LoginForm : Form { } public class AboutForm : Form { } Type typLoginForm = typeof(LoginForm); LoginForm lf = GetForm("myformid"); lf.ShowDialog(); public T GetForm(string form_id) where T: Form { return pool[form_id] as T; } You can change the Dictionary to Dictionary> to add more than 1 item under the same key. Or Dictionary> to get a pool item with its type instead of form_id value which is string. Fire and Water, Love and Death, Sex and the City? :)
-
Dictionary pool = new Dictionary(10); pool.Add("myformid", new LoginForm()); pool.Add("myAboutformid", new AboutForm()); public class LoginForm : Form { } public class AboutForm : Form { } Type typLoginForm = typeof(LoginForm); LoginForm lf = GetForm("myformid"); lf.ShowDialog(); public T GetForm(string form_id) where T: Form { return pool[form_id] as T; } You can change the Dictionary to Dictionary> to add more than 1 item under the same key. Or Dictionary> to get a pool item with its type instead of form_id value which is string. Fire and Water, Love and Death, Sex and the City? :)
Thanks. But this way I'll be creating a new Form eacht time the GetForm function is called, while all I really want is a reference to an existing instance of the form if it exists, or a reference to a new instance if it doesn't. This works. The real problem for me is that the pool is serializable: Some basic data (location, position) can be stored and retrieved from a file. I save the info when the application is exited. When I start it up I want it to reconstruct each instance using its respective constructor...
Standards are great! Everybody should have one!
-
Thanks. But this way I'll be creating a new Form eacht time the GetForm function is called, while all I really want is a reference to an existing instance of the form if it exists, or a reference to a new instance if it doesn't. This works. The real problem for me is that the pool is serializable: Some basic data (location, position) can be stored and retrieved from a file. I save the info when the application is exited. When I start it up I want it to reconstruct each instance using its respective constructor...
Standards are great! Everybody should have one!
No, you won't be creating a new Form each time. It was just an example, you can replace: pool.Add("myformid", new LoginForm()); pool.Add("myAboutformid", new AboutForm()); as pool.Add("myformid", myAlreadyCreatedLoginForm); pool.Add("myAboutformid", myAlreadyCreatedAboutForm()); also: GetForm(...) code I sent you does not create anything. Do you see any "new" keyword in the code/or am I blind? Result: - You have an assembly created in you bin\debug folder in which your Forms are also embedded. This is your store to create the Forms at run-time. You want to store some configuration related to your forms, so what you need is to store this configuration like size and location somewhere like an xml file. If you've done it(you've written Some basic data(location, position) can be retrieved from a file), then you want to get a Form from the pool. Then your pool is the one which is responsible of returning an instance of the Form type if there is already one, created in pre-call to GetForm(...) or you want to create a new instance with the configuration parameters stored using reflection. If this is what you want: // The configurtation of the Form you serialize/deserialize public class FormConfig : ConfigurationProperty /*or string, or xml file, or whatever you want */ { } public T GetForm(string form_id) where T: Form { if(pool.ContainsKey(form_id)) { return pool[form_id] as T; } else { // you may have a look at other overloaded method(s) of Activator.CreateInstance return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T; } } public FormConfig GetConfig(string key) { return ..... // return the deserialized config } public FormConfig GetConfig(Type key) { return ..... // return the deserialized config } "Peace at home, peace in the world" Mustafa Kemal Atatürk(the founder of the Republic of Turkey and its first President.))
-
No, you won't be creating a new Form each time. It was just an example, you can replace: pool.Add("myformid", new LoginForm()); pool.Add("myAboutformid", new AboutForm()); as pool.Add("myformid", myAlreadyCreatedLoginForm); pool.Add("myAboutformid", myAlreadyCreatedAboutForm()); also: GetForm(...) code I sent you does not create anything. Do you see any "new" keyword in the code/or am I blind? Result: - You have an assembly created in you bin\debug folder in which your Forms are also embedded. This is your store to create the Forms at run-time. You want to store some configuration related to your forms, so what you need is to store this configuration like size and location somewhere like an xml file. If you've done it(you've written Some basic data(location, position) can be retrieved from a file), then you want to get a Form from the pool. Then your pool is the one which is responsible of returning an instance of the Form type if there is already one, created in pre-call to GetForm(...) or you want to create a new instance with the configuration parameters stored using reflection. If this is what you want: // The configurtation of the Form you serialize/deserialize public class FormConfig : ConfigurationProperty /*or string, or xml file, or whatever you want */ { } public T GetForm(string form_id) where T: Form { if(pool.ContainsKey(form_id)) { return pool[form_id] as T; } else { // you may have a look at other overloaded method(s) of Activator.CreateInstance return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T; } } public FormConfig GetConfig(string key) { return ..... // return the deserialized config } public FormConfig GetConfig(Type key) { return ..... // return the deserialized config } "Peace at home, peace in the world" Mustafa Kemal Atatürk(the founder of the Republic of Turkey and its first President.))
Hmm, I think I might have been having a bit of an off day in explaining what I was aiming for, but you guessed about right the second time. This line of code was close enough to what I was looking for:
return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T;
I've just been staring at the same CreateInstance method without ever realizing there's a bunch of overloads to choose from. Thanks very much for the help :).
Standards are great! Everybody should have one!
-
Hmm, I think I might have been having a bit of an off day in explaining what I was aiming for, but you guessed about right the second time. This line of code was close enough to what I was looking for:
return Activator.CreateInstance(T, new object[]{GetConfig(typeof(mySerializedForm))}) as T;
I've just been staring at the same CreateInstance method without ever realizing there's a bunch of overloads to choose from. Thanks very much for the help :).
Standards are great! Everybody should have one!