Cannot store an array of classes - c#

I am trying to store an array of classes which I can initialise later on. I am trying to do it like so:
Type[] x = { className };
However, I am getting the following error:
'myNamespace.className' is a 'type' but it is used like a 'variable'
Any guidance would be appreciated.

Use the typeof operator, which is used to obtain a System.Typefor a type.
Type[] x = { typeof(className) };
EDIT:
In response to your comment: to create an instance of the type from a System.Type, use an appropriate overload of the Activator.CreateInstance method.
E.g.
Type t = typeof(int);
// Boxed Int32 with value 0
object o = Activator.CreateInstance(t);
In your case, since you know the base-type of the class, you can of course cast the return-value to the base-type.

Related

'type' is a variable but is used like a type [duplicate]

The following doesn't work, of course. Is there a possible way, which is pretty similar like this?
Type newObjectType = typeof(MyClass);
var newObject = givenObject as newObjectType;
newObjectType is an instance of the Type class (containing metadata about the type) not the type itself.
This should work
var newObject = givenObject as MyClass;
OR
var newObject = (MyClass) givenObject;
Casting to an instance of a type really does not make sense since compile time has to know what the variable type should be while instance of a type is a runtime concept.
The only way var can work is that the type of the variable is known at compile-time.
UPDATE
Casting generally is a compile-time concept, i.e. you have to know the type at compile-time.
Type Conversion is a runtime concept.
UPDATE 2
If you need to make a call using a variable of the type and you do not know the type at compile time, you can use reflection: use Invoke method of the MethodInfo on the type instance.
object myString = "Ali";
Type type = myString.GetType();
MethodInfo methodInfo = type.GetMethods().Where(m=>m.Name == "ToUpper").First();
object invoked = methodInfo.Invoke(myString, null);
Console.WriteLine(invoked);
Console.ReadLine();
You can check if the type is present with IsAssignableFrom
if(givenObject.GetType().IsAssignableFrom(newObjectType))
But you can't use var here because type isn't known at compile time.
I recently had the case, that I needed to generate some code like in Tomislav's answer. Unfortunately during generation time the type T was unknown. However, a variable containing an instance of that type was known. A solution dirty hack/ workaround for that problem would be:
public void CastToMyType<T>(T hackToInferNeededType, object givenObject) where T : class
{
var newObject = givenObject as T;
}
Then this can be called by CastToMyType(instanceOfNeededType, givenObject) and let the compiler infer T.
You can use Convert.ChangeType. According to msdn, it
returns an object of a specified type whose value is equivalent to a
specified object.
You could try the code below:
Type newObjectType = typeof(MyClass);
var newObject = Convert.ChangeType(givenObject, newObjectType);
Maybe you can solve this using generics.
public void CastToMyType<T>(object givenObject) where T : class
{
var newObject = givenObject as T;
}

Get the actual type from a Type variable

I am trying to get a type from a Type variable. For example:
Type t = typeof(String);
var result = SomeGenericMethod<t>();
An error happens on the second line, because t is not a type, it's a variable. Any way to make it a type?
To make an instance of a generic based on a Type, you can use reflection to get an instance of the generic with the type you want to use, then use Activator to create that instance:
Type t = typeof (string); //the type within our generic
//the type of the generic, without type arguments
Type listType = typeof (List<>);
//the type of the generic with the type arguments added
Type generictype = listType.MakeGenericType(t);
//creates an instance of the generic with the type arguments.
var x = Activator.CreateInstance(generictype);
Note that x here will be an object. To call functions on it, such as .Sort(), you'd have to make it a dynamic.
Please Note that this code is hard to read, write, maintain, reason about, understand, or love. If you have any alternatives to needing to use this sort of structure, explore those thoroughly.
Edit: You can also cast the object you receive from the Activator, such as (IList)Activator.CreateInstance(genericType). This will give you some functionality without having to resort to dynamics.
No, you cannot know the value of a Type object at compile time, which is what you would need to do in order to use a Type object as an actual type. Whatever you're doing that needs to use that Type will need to do so dynamically, and not require having a type known at compile time.
An ugly workaround using reflection:
Class with generic Method
public class Dummy {
public string WhatEver<T>() {
return "Hello";
}
}
Usage
var d = new Dummy();
Type t = typeof(string);
var result = typeof(Dummy).GetMethod("WhatEver").MakeGenericMethod(t).Invoke(d, null);
On class instantiation see Max's solution

How do I use System.Type variable to call a generic method?

Type valueType = Type.GetType("int");
object value = new List<valueType>();
The first line compiles fine, But the 2nd does not.
How can I create a generic list (or call a generic method)
object value = foo<valueType>();
By only having a string representation of the type?
My end goal is actually to take two string "int" and "5 (as an example) and assign the value of 5 to the object [and eventually to the userSettings]. But I have a method that will convert "5" to the actual value if I can tell the generic method it is of type int based on the string representation.
T StringToValue<T>(string s)
{
return (T)Convert.ChangeType(s, typeof(T));
}
Update: I was thinking that creating a generic object and calling a generic method would use the same methodology, but I guess I was wrong. How can I call the generic method?
Type.GetType("int") returns null. This is invalid because int is just a keyword in the C# language, which is equivalent to the type System.Int32. It has no special meaning to the .NET CLR, so it's not usable in reflection. You might have meant typeof(int) or Type.GetType("System.Int32") (or it doesn't really matter, because that was just an example).
Anyway, once you have the right Type, this is how you can get your list. The key is MakeGenericType.
Type valueType = typeof(int);
object val = Activator.CreateInstance(typeof(List<>).MakeGenericType(valueType));
Console.WriteLine(val.GetType() == typeof(List<int>)); // "True" - it worked!
I will share an example from Jeffrey Richter's book CLR Via C# about constructing generic types, this is not specific to the question but will help guide you to finding the appropriate way of doing what you want:
public static class Program {
public static void Main() {
// Get a reference to the generic type's type object
Type openType = typeof(Dictionary<,>);
// Close the generic type by using TKey=String, TValue=Int32
Type closedType = openType.MakeGenericType(typeof(String), typeof(Int32));
// Construct an instance of the closed type
Object o = Activator.CreateInstance(closedType);
// Prove it worked
Console.WriteLine(o.GetType());
}
}
Will display: Dictionary`2[System.String,System.Int32]
try this:
Type valueType = Type.GetType("System.Int32");
Type listType = typeof(List<>).MakeGenericType(valueType);
IList list = (IList) Activator.CreateInstance(listType);
// now use Reflection to find the Parse() method on the valueType. This will not be possible for all types
string valueToAdd = "5";
MethodInfo parse = valueType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static);
object value = parse.Invoke(null, new object[] { valueToAdd });
list.Add(value);

How to use the type 'Type'

I know that I can use the type string as:
string someString = "This is my string";
I am not sure how to use the type Type
Type someType = someString.GetType();
How could I create a variable based on that type. I want to do something like
someType someOtherString = "here is another string";
//string
In other words, how could I create a variable based on some type?
There are a few ways to go about this, but the simplest would be to use the Activator class.
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
Example:
Type t = someClassInstance.GetType();
object o = Activator.CreateInstance(t);
Variable types have to be known at declaration time. You can declare a variable of type object and then dynamically create an instance of a type which you only know about at execution time, but you can't dynamically declare a variable like that.
The closest you could get would be to create a generic type and instantiate that using a type argument specified with reflection. Then you really would have a variable of the right type - but you wouldn't be able to do anything particularly useful with it.
It's important to distinguish between the type of a variable and the type of the object a variable's value may refer to. For example:
object foo = Activator.CreateInstance(someType);
will end up with a variable of type object, but the value of foo will be a reference to an instance of whatever type someType refers to.
Try
var object = Activator.CreateInstance(myType);
Starting from C# 3 you can do:
var someOtherString = "here is another string";
This way you don't care what's the type, var is type "joker" and save you the need to know the type at declaration time.
Hope that's what you mean?
use Assembly.CreateInstance()
Type type = typeof(String);
Assembly asm = Assembly.GetExecutingAssembly();
object blah = asm.CreateInstance(type.FullName);

Creating an instance of variable with reflection

I want to create an instance of type t with reflection, that is
Type t = typeof(string);
string s = (t)Activator.CreateInstance(t); // this fails because of convertion
string s = Activator.CreateInstance(t) as t // also fails
Is there a way to perform such a convertion?
Thanks.
Yes. You have to convert to string, not to t. You may want a generic method, alternatively:
public T GetInstance<T>()
{
Type t = typeof(T);
T s = (T)Activator.CreateIstance(t);
return s;
}
As things stand you are attempting to cast an object that is actually an instance of System.String to type System.Type...
Try this:
string s = (string)Activator.CreateInstance(t);
Activator.CreateInstance returns an instance boxed in an object so it must be cast to the correct type before you can use it.
In your example t is a Type object variable and not a type reference. You must either specify the type directly as in my example or you can use generics.

Categories