I'm trying to convert a generic method parameter to its type. The compiler is saying that I can't convert it
public ProvideRequest ProvideRequest<T>(int numberOfLines,
string ServiceType,
T addressIdentifier)
{
var provideRequest = new ProvideRequest();
provideRequest.NumberOfLines = numberOfLines;
provideRequest.ServiceType = ServiceType;
Type t = typeof(T);
switch (t.GetType().Name)
{
case nameof(GoldAddressKeyIdentifierType):
provideRequest.RequestIdentifier =
Convert.ChangeType(addressIdentifier, typeof(GoldAddressKeyIdentifierType))
break;
}
return provideRequest;
}
Any help with this would be appreciated.
The problem is that when calling t.GetType() you don´t get the generic type but simply System.Type which is the runtime-type of t. What you want instead is the name of the generic type, which you can get via :
switch(typeof(T).Name)
Furthermore Name returns a string, so you have to write your cases as follows:
case MyNamepscae.GoldAddressKeyIdentifierType:
However I´d strongly recommend not to lery on typenames, just make a switch on the actual type itself. However the switchstatement allows only strings, so use an if instead:
if(typeof(T) == typeof(GoldAddressKeyIdentifierType))
Type t = typeof(T); // type of T
switch (t.GetType().Name)
This switch is a mistake probably. t is of type Type. So t.GetType() is System.RuntimeType, so t.GetType().Name is always "System.RuntimeType" you know.
As far as I understand your problem, you need to remove .GetType(), you need
switch(t.Name)
I suggest comparing two Types:
...
if (typeof(T) == typeof(GoldAddressKeyIdentifierType))
provideRequest.RequestIdentifier =
Convert.ChangeType(addressIdentifier, typeof(GoldAddressKeyIdentifierType));
return provideRequest;
However, generics (<T>) should work as generic type, any special conditions are bad parctice.
Since you know it is of type GoldAddressKeyIdentifierType, you should be able to cast the object as the class in your case method
provideRequest.RequestIdentifier = (GoldAddressKeyIdentifierType)addressIdentifier;
Related
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
I have an array of PropertyInfo representing the properties in a class. Some of these properties are of type ICollection<T>, but T varies across the properties - I have some ICollection<string>, some ICollection<int>, etc.
I can easily identify which of the properties are of type ICollection<> by using the GetGenericTypeDefinition() method on type, but I am finding it impossible to get the type of T - the int or string in my example above.
Is there a way to do this?
IDocument item
PropertyInfo[] documentProperties = item.GetType().GetProperties();
PropertyInfo property = documentProperties.First();
Type typeOfProperty = property.PropertyType;
if (typeOfProperty.IsGenericType)
{
Type typeOfProperty = property.PropertyType.GetGenericTypeDefinition();
if (typeOfProperty == typeof(ICollection<>)
{
// find out the type of T of the ICollection<T>
// and act accordingly
}
}
If you know it'll be ICollection<X> but don't know X, that's fairly easy with GetGenericArguments:
if (typeOfProperty.IsGenericype)
{
Type genericDefinition = typeOfProperty.GetGenericTypeDefinition();
if (genericDefinition == typeof(ICollection<>)
{
// Note that we're calling GetGenericArguments on typeOfProperty,
// not genericDefinition.
Type typeArgument = typeOfProperty.GetGenericArguments()[0];
// typeArgument is now the type you want...
}
}
It gets harder when the type is some type which implements ICollection<T> but may itself be generic. It sounds like you're in a better position :)
I believe this is what you are looking for:
typeOfProperty.GetGenericArguments()[0];
That will return you the T part of a generic List<T> for example.
Jon's solution will yield T. Depending on the context, you might need to access the getter return type instead in order to get int, string, etc. For example...
// The following example will output "T"
typeOfProperty = property.PropertyType.GetGenericTypeDefinition();
Type genericDefinition = typeOfProperty.GetGenericTypeDefinition();
if (genericDefinition == typeof(ICollection<>))
{
Type t1 = typeOfProperty.GetGenericArguments()[0];
Console.WriteLine(t1.ToString());
}
// Instead you might need to do something like the following...
// This example will output the declared type (e.g., "Int32", "String", etc...)
typeOfProperty = property.GetGetMethod().ReturnType;
if (typeOfProperty.IsGenericType)
{
Type t2 = typeOfProperty.GetGenericArguments()[0];
Console.WriteLine(t2.ToString());
}
I am working in c# with .net 2.0 (i know its old)
Here is my setup:
struct propertyType
{
System.type type;
}
public class DataProperties
{
private Dictionary<propertyType, object> properties;
public void setProperty(propertyType key, object value)
{
if(value.getType == key.type) //make sure they are adding valid data
properties.add(key, value);
}
public T getProperty<T> (propertyType key)
{
return (T)properties[key];
}
}
Then in my class that needs to pull properties it would look like
//this would be declared somewhere else for use by multiple classes.
//but for example sake its here
propertyType hash;
hash.type = typeof(byte[]);
byte[] hashCode = DataSet.properties.GetProperty<hash.type>(hash);
Now the last line is the one that doesnt work, but I'd like to work. I think the problem is that it doesnt like having a variable as the Type. In actual use there will be many different PropertyType objects so I want a way to get the properties out and cast to the correct type easily.
Does anyone know if it is for sure that the variable as the type is the problem. But at compile time it will know what hash.type is so its not that its an unknown value at compile time.
No, it is an unknown value at compile-time, as far as the compiler is concerned. Just because you've set it in the previous line doesn't mean the compiler really knows the value.
You simply can't use variables to specify type arguments in C# generics, other than with reflection. A type argument has to be the name of a type or another type parameter - it can't be an expression which evaluates to a System.Type.
the problem is that it doesnt like having a variable as the Type
That's right. There's no way to do this that keeps compile-time safety. It's possible to use reflection to call the getProperty method with a generic type that you only know at run time, but generics don't gain you anything in this case.
Since you're only using generics to do a type cast, why not add an overload to getProperty that's not generic and returns object?
As Jon Skeet and others have said, this cannot be done without reflection. So, here's some reflection code that should get you on the right track:
Type myGenericParam = typeof(byte[]);
MethodInfo method = typeof(DataProperties).GetMethod("getProperty").MakeGenericMethod(new[] { myGenericParam });
DataProperties foo = new DataProperties();
byte[] result = (byte[])method.Invoke(foo, new[] { /*parameters go here in order */ });
I have this XML document
<AdditionalParameters>
<PublishToPdf Type ="System.Boolean">False</PublishToPdf>
</AdditionalParameters>
in my code and I'm trying to build an array of arguments containing the <PublishToPdf> node.
object test = (object) ((typeof(publishNode.Attributes["Type"].value)) publishNode.InnerText);
This breaks at compile time of course. I can't figure out how to cast the publishNode.InnerText('false') to a runtime defined object of type specified in the XML file and store it in an object (which will conserve the type).
You can use Convert.ChangeType :
object value = Convert.ChangeType(stringValue, destinationType);
You can't do exactly what you're trying to do. First, the typeof keyword does not allow for dynamic evaluation at runtime. There are means by which to do this using reflection, with methods like Type.GetType(string), but the Type objects returned from these reflective functions can't be used for operations like casting.
What you need to do is provide a means of converting your type to and from a string representation. There is no automatic conversion from any arbitrary type. For your example, you can use bool.Parse or bool.TryParse, but those are specific to the bool type. There are similar methods on most primitive types.
The simple solution, assuming there is a limited number of possible types;
object GetValueObject(string type, string value)
{
switch (type)
{
case "System.Boolean":
return Boolean.Parse(value);
case "System.Int32":
return Int32.Parse(value);
...
default:
return value;
}
}
var type = publishNode.Attributes["Type"].value;
var value = publishNode.InnerText;
var valueObject = GetValueObject(type, value);
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.