Casting a variable using a Type variable
Asked Answered
L

11

393

In C# can I cast a variable of type object to a variable of type T where T is defined in a Type variable?

Lipscomb answered 9/6, 2009 at 21:39 Comment(4)
Not strictly on-topic, but you seem fuzzy enough about what "cast" means that it might be a good idea to understand precisely what the purpose and semantics of the cast operator are. Here's a good start: blogs.msdn.com/ericlippert/archive/2009/03/19/…Pharmaceutics
I thought I had come up with something. If you have a Type variable, you can use reflection to create an instance of that type. And then you can use a generic method to return the type you want by inferring it from a parameter of that type. Unfortunately, any reflection method that creates an instance of a type will have a return type of object, so your generic CastByExample method will use object as well. So there's really no way to do this, and even if there was, what would you do with the newly-cast object? You couldn't use its methods or anything because you don't know its type.Scoot
@KyleDelaney Thank you, I completely agree! As I tried to explain in my answer, it isn't really that useful to cast something to a different thing without at some point defining the Type that you are actually using. The whole point of types is compiler time type checking. If you just need to do calls on the object, you can use object or dynamic. If you want to dynamically load external modules, you can have the classes share a common interface and cast the object to that. If you don't control the third party code, create small wrappers and implement the interface on that.Thorough
Updated link to Eric Lippert's blog ericlippert.com/2009/03/03/representation-and-identityNicholson
T
267

Here is an example of a cast and a convert:

using System;

public T CastObject<T>(object input) {   
    return (T) input;   
}

public T ConvertObject<T>(object input) {
    return (T) Convert.ChangeType(input, typeof(T));
}

Edit:

Some people in the comments say that this answer doesn't answer the question. But the line (T) Convert.ChangeType(input, typeof(T)) provides the solution. The Convert.ChangeType method tries to convert any Object to the Type provided as the second argument.

For example:

Type intType = typeof(Int32);
object value1 = 1000.1;

// Variable value2 is now an int with a value of 1000, the compiler 
// knows the exact type, it is safe to use and you will have autocomplete
int value2 = Convert.ChangeType(value1, intType);

// Variable value3 is now an int with a value of 1000, the compiler
// doesn't know the exact type so it will allow you to call any
// property or method on it, but will crash if it doesn't exist
dynamic value3 = Convert.ChangeType(value1, intType);

I've written the answer with generics, because I think it is a very likely sign of code smell when you want to cast a something to a something else without handling an actual type. With proper interfaces that shouldn't be necessary 99.9% of the times. There are perhaps a few edge cases when it comes to reflection that it might make sense, but I would recommend to avoid those cases.

Edit 2:

Few extra tips:

  • Try to keep your code as type-safe as possible. If the compiler doesn't know the type, then it can't check if your code is correct and things like autocomplete won't work. Simply said: if you can't predict the type(s) at compile time, then how would the compiler be able to?
  • If the classes that you are working with implement a common interface, you can cast the value to that interface. Otherwise consider creating your own interface and have the classes implement that interface.
  • If you are working with external libraries that you are dynamically importing, then also check for a common interface. Otherwise consider creating small wrapper classes that implement the interface.
  • If you want to make calls on the object, but don't care about the type, then store the value in an object or dynamic variable.
  • Generics can be a great way to create reusable code that applies to a lot of different types, without having to know the exact types involved.
  • If you are stuck then consider a different approach or code refactor. Does your code really have to be that dynamic? Does it have to account for any type there is?
Thorough answered 17/7, 2009 at 20:36 Comment(28)
How do you do this, my c# compiler complains about "return (T) input".Globetrotter
I dont know how is this helping OP. She has a type variable, not T as such.Reames
@nawfal, basically the line Convert.ChangeType(input, typeof(T)); gives the solution. You can easily replace typeof(T) with an existing type variable. A better solution (if possible) would be to prevent the dynamic type all together.Thorough
@Zyphrax, no it still requires a cast to T which is not available.Reames
@nawfal, you can store it in a dynamic type or in object. But it will be converted to the new type (if conversion between those types is supported/implemented). I don't see what the use is of casting or converting something to something else and never define the actual type.Thorough
I know the resultant object is really is of type T but still you only get an object as a reference. hmm, I found the question interesting in the premise that OP has only the Type variable and no other info. As if the method signature is Convert(object source, Type destination) :) Nevertheless i get ur pointReames
How is this a solution to this question? I've got the same problem and I do not have a generic <T>. I only have a type variable.Positivism
@NuriTasdemir Well, the line (T) Convert.ChangeType(input, typeof(T)) looks like what you need. But again, the need to cast a something to a something else without a definition of the type somewhere feels a bit like code smell (maybe with a few exceptions when working with reflection).Thorough
@Zyphrax That's right. It was a generated class via reflection. At the end I wrote a generic method for casting and called that by using MakeGenericMethod.Positivism
As an example of where this is useful, I have a list of serialized data stored in a SharePoint work item queue. I need to dynamically deserialize to various work types to concrete objects, and I'm not going to know which type I need until runtime.Breadbasket
@JimYarbro Fair enough, Sharepoint is often an exception to the rule ;)Thorough
Zyphrax, as far as I can tell, your solution would only work if the type is known at development time. I don't see how it could be used to case "dynamically" so to speak. That is to say, it doesn't solve the problem of needing to cast to a type that is retrieved from a variable rather than being hard-coded in.Scoot
@KyleDelaney Are you working on code that uses reflection? Otherwise, like I said above, it is probably a sign of code smell that you need to cast a something to a something else without handling an actual type.Thorough
Yes, I use reflection, @Zyphrax. Let's say I have an ICollector that exposes Source and Type properties and an Execute method. Implementations would include MsSqlCollector or MySqlCollector. If tomorrow a customer asks for a PostgressCollector I would like to build that into a separate library that I load at runtime using reflection. At runtime a user can compose his "run" from available Collectors. In my main assembly I need to instantiate and execute the correct one without knowing which ones are available at development time. I have no clue how to go about.Levirate
@Levirate Wouldn't your ICollector interface already take care of that? You create a dynamic collector with something like System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(...) and then pass it through as an ICollector. No need to cast it to a MySqlCollector or PostgressCollector.Thorough
Thx @Zyphrax. Your comment doesn't help the OP since it doesn't involve a cast, but +1 for putting me on the right path nevertheless.Levirate
@Levirate thank you. I've edited my answer to add a bit of clarification.Thorough
For anybody looking for Convert, it comes from System.Heliacal
@Zyphrax I'm also here working with reflection. I only have a type variable as described in the question. This is not an answer to that scenario, but I know you predicament with all the upvotes from people not having the same problem as described in the question :)Ellett
@Ellett What is your scenario? Please note my last alinea, if you don't have a static Type in there somewhere it is likely a case of code smell / a design issue.Thorough
Well, I want to know if there is a solution for this specific scenario regardless of whether someone thinks it's good or bad code, and this is not answering the question :)Ellett
@Ellett The Convert.ChangeType method can be used to convert an object to a different type using a type variable (see the second ChangeType call in my example). It is not my intention to judge your code, it was merely a suggestion that there is probably a better solution for your scenario out there.Thorough
I've added an example of how to use ChangeType with a Type variable.Thorough
This answer also doesn't allow you to access the fields of the type, it gives the error "'object' does not contain a definition for '<fieldName>' ...". It really doesn't answer the question at all.Cosmism
@Cosmism If you store the result in an object you won't have access to any of the fields, properties or methods. See value3 in my example on how to use it typed.Thorough
@Zyphrax value3 doesn't use a Type variable, which was the point of the question. If you know what type the variable is, yes it is easy to cast it and use it, but the whole point is that you don't know, all you have is a Type to work with. This still doesn't answer the question properly.Cosmism
@Cosmism Can you explain your case to me? I've updated the examples, maybe this clarifies the way you can use the Convert.ChangeType method for different scenarios. It sounds to me that you want to convert a something to a different thing, refer to it with a type and expect to have type safety. You can always store it in a dynamic and do with it as you please.Thorough
The type used in Convert.ChangeType(value, type) must implement IConvertible or it will throw System.InvalidCastException.Mouldon
T
163

Other answers do not mention "dynamic" type. So to add one more answer, you can use "dynamic" type to store your resulting object without having to cast converted object with a static type.

dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();

Keep in mind that with the use of "dynamic" the compiler is bypassing static type checking which could introduce possible runtime errors if you are not careful.

Also, it is assumed that the obj is an instance of Type typeVar or is convertible to that type.

Talia answered 13/3, 2015 at 12:27 Comment(8)
This is the correct answer. Without the dynamic keyword typeof(changedObj) is "object". With the dynamic keyword it works flawlessly and typeof(changedObject) correctly reflects the same type as typeVar. Additionally you don't need to (T) cast which you can't do if you don't know the type.Aikido
I've got "Object must implement IConvertible" exception while using this solution. Any help?Positivism
@NuriTasdemir Hard to tell, but I believe the conversion you are doing is not possible without IConvertible. What are the types involved in your conversion?Talia
While this works, there is a performance penalty with using dynamics. I would recommend against using them unless you are working with other runtimes (which is what dynamics were designed for).Unruly
How come this is an answer? 99.99% types do not implement IConvertible, so in 99.99% of cases it will not work.Ambsace
@Ambsace we used this solution for a small part of an app without any issues. The assumption here is that the obj instance in the code is already of typeVar and this is known. This obj variable can be of different types and the Type is already known in typeVar.Talia
!!! in my case, that the only thing working, because with dynamic typeof(changeObj) would be evaluated correctly github.com/dotnet/efcore/issues/14521Stipulate
in my case, I have known the type sent to the ChangeType method, because it is defined by the system. So this approach is acceptable and works well. The type will be checked in runtime. This helps me to make polymorphism in a methodAnodic
H
21

Here is my method to cast an object but not to a generic type variable, rather to a System.Type dynamically:

I create a lambda expression at run-time using System.Linq.Expressions, of type Func<object, object>, that unboxes its input, performs the desired type conversion then gives the result boxed. A new one is needed not only for all types that get casted to, but also for the types that get casted (because of the unboxing step). Creating these expressions is highly time consuming, because of the reflection, the compilation and the dynamic method building that is done under the hood. Luckily once created, the expressions can be invoked repeatedly and without high overhead, so I cache each one.

private static Func<object, object> MakeCastDelegate(Type from, Type to)
{
    var p = Expression.Parameter(typeof(object)); //do not inline
    return Expression.Lambda<Func<object, object>>(
        Expression.Convert(Expression.ConvertChecked(Expression.Convert(p, from), to), typeof(object)),
        p).Compile();
}

private static readonly Dictionary<Tuple<Type, Type>, Func<object, object>> CastCache
= new Dictionary<Tuple<Type, Type>, Func<object, object>>();

public static Func<object, object> GetCastDelegate(Type from, Type to)
{
    lock (CastCache)
    {
        var key = new Tuple<Type, Type>(from, to);
        Func<object, object> cast_delegate;
        if (!CastCache.TryGetValue(key, out cast_delegate))
        {
            cast_delegate = MakeCastDelegate(from, to);
            CastCache.Add(key, cast_delegate);
        }
        return cast_delegate;
    }
}

public static object Cast(Type t, object o)
{
    return GetCastDelegate(o.GetType(), t).Invoke(o);
}

Note that this isn't magic. Casting doesn't occur in code, as it does with the dynamic keyword, only the underlying data of the object gets converted. At compile-time we are still left to painstakingly figure out exactly what type our object might be, making this solution impractical. I wrote this as a hack to invoke conversion operators defined by arbitrary types, but maybe somebody out there can find a better use case.

Hyperparathyroidism answered 13/7, 2015 at 9:49 Comment(3)
Requires using System.Linq.Expressions;Equivalent
For me this suffers from the same problem as Zyphrax's answer. I cannot invoke methods on the returned object because it is still of "object" type. Whether I use his method ("a" below) or your method ("b" below) I get the same error on the (t) cast - "'t' is a variable but it is used like a type. Type t = typeof(MyGeneric<>).MakeGenericType(obj.OutputType); var a = (t)Convert.ChangeType(obj, t); var b = (t)Caster.Cast(t, obj);Edette
@Edette Zyphrax's original answer uses generics and type variables, not Type. You can't cast using normal casting syntax if all you have is the Type object. If you want to be able to use the object as some type T at compile time, not runtime, you need to cast it using a type variable or just the actual type name. You can do the former using Zaphrax's answer.Risa
H
8

Putting boxing and unboxing aside for simplicity, there's no specific runtime action involved in casting along the inheritance hierarchy. It's mostly a compile time thing. Essentially, a cast tells the compiler to treat the value of the variable as another type.

What you could do after the cast? You don't know the type, so you wouldn't be able to call any methods on it. There wouldn't be any special thing you could do. Specifically, it can be useful only if you know the possible types at compile time, cast it manually and handle each case separately with if statements:

if (type == typeof(int)) {
    int x = (int)obj;
    DoSomethingWithInt(x);
} else if (type == typeof(string)) {
    string s = (string)obj;
    DoSomethingWithString(s);
} // ...
Harbourage answered 9/6, 2009 at 21:43 Comment(5)
Could you please explain that clearer in relation to my question?Lipscomb
What I'm trying to explain is, what you would be able to do after that? You can't do much as the C# compiler requires static typing to be able to do a useful thing with the objectHarbourage
You're right. I know the expected types of two variable which are sent to the method as type 'object'. I want to cast to expected types stored in variables, and add them to collection. Much easier to branch on type and attempt a normal cast and catch errors.Lipscomb
Your answer is good, but just to be nit-picky, I note that casts never affect variables. It is never legal to cast a variable to a variable of another type; variable types are invariant in C#. You can only cast the value stored in the variable to another type.Pharmaceutics
Does C# 4.0's introduction of dynamic typing change this answer any?Gerous
L
7

After not finding anything to get around "Object must implement IConvertible" exception when using Zyphrax's answer (except for implementing the interface).. I tried something a little bit unconventional and worked for my situation.

Using the Newtonsoft.Json nuget package...

var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);
Lockhart answered 14/6, 2019 at 20:27 Comment(1)
This works for objects, but what about classes?Puttier
R
4

How could you do that? You need a variable or field of type T where you can store the object after the cast, but how can you have such a variable or field if you know T only at runtime? So, no, it's not possible.

Type type = GetSomeType();
Object @object = GetSomeObject();

??? xyz = @object.CastTo(type); // How would you declare the variable?

xyz.??? // What methods, properties, or fields are valid here?
Radiomicrometer answered 9/6, 2009 at 21:44 Comment(3)
If youre using a generic class, that defines a method with return value of type T, you could need to do that. E.g. parsing a string to an instance of T and returning that.Globetrotter
This is not the correct answer fortunately. See maulik13's answer.Aikido
Where in Heaven's name do you find a CastTo method on Object?Poppycock
F
4

When it comes to casting to Enum type:

private static Enum GetEnum(Type type, int value)
    {
        if (type.IsEnum)
            if (Enum.IsDefined(type, value))
            {
                return (Enum)Enum.ToObject(type, value);
            }

        return null;
    }

And you will call it like that:

var enumValue = GetEnum(typeof(YourEnum), foo);

This was essential for me in case of getting Description attribute value of several enum types by int value:

public enum YourEnum
{
    [Description("Desc1")]
    Val1,
    [Description("Desc2")]
    Val2,
    Val3,
}

public static string GetDescriptionFromEnum(Enum value, bool inherit)
    {
        Type type = value.GetType();

        System.Reflection.MemberInfo[] memInfo = type.GetMember(value.ToString());

        if (memInfo.Length > 0)
        {
            object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), inherit);
            if (attrs.Length > 0)
                return ((DescriptionAttribute)attrs[0]).Description;
        }

        return value.ToString();
    }

and then:

string description = GetDescriptionFromEnum(GetEnum(typeof(YourEnum), foo));
string description2 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum2), foo2));
string description3 = GetDescriptionFromEnum(GetEnum(typeof(YourEnum3), foo3));

Alternatively (better approach), such casting could look like that:

 private static T GetEnum<T>(int v) where T : struct, IConvertible
    {
        if (typeof(T).IsEnum)
            if (Enum.IsDefined(typeof(T), v))
            {
                return (T)Enum.ToObject(typeof(T), v);
            }

        throw new ArgumentException(string.Format("{0} is not a valid value of {1}", v, typeof(T).Name));
    }
Floriated answered 27/8, 2018 at 9:19 Comment(2)
isn't simplier way to just cast int to given enum? smth like that: int value = 3; var yourEnum = (YourEnum) value;Oestrin
@KamilZ tbh I don't fully remember this specific case, I think with plain cast you'd be unable to access enum attributes #37892224 I no longer use C# profesionally.Floriated
F
1

I will never understand why you need up to 50 reputation to leave a comment but I just had to say that @Curt answer is exactly what I was looking and hopefully someone else.

In my example, I have an ActionFilterAttribute that I was using to update the values of a json patch document. I didn't what the T model was for the patch document to I had to serialize & deserialize it to a plain JsonPatchDocument, modify it, then because I had the type, serialize & deserialize it back to the type again.

Type originalType = //someType that gets passed in to my constructor.

var objectAsString = JsonConvert.SerializeObject(myObjectWithAGenericType);
var plainPatchDocument = JsonConvert.DeserializeObject<JsonPatchDocument>(objectAsString);

var plainPatchDocumentAsString= JsonConvert.SerializeObject(plainPatchDocument);
var modifiedObjectWithGenericType = JsonConvert.DeserializeObject(plainPatchDocumentAsString, originalType );
Forepeak answered 15/5, 2020 at 1:51 Comment(1)
For anyone encountering this, this method will be extremely slow even compared to reflection, because JsonConvert is doing a lot more under the hood than just converting those values!Spadefish
O
0

If you need to cast objects at runtime without knowing destination type, you can use reflection to make a dynamic converter.

This is a simplified version (without caching generated method):

    public static class Tool
    {
            public static object CastTo<T>(object value) where T : class
            {
                return value as T;
            }

            private static readonly MethodInfo CastToInfo = typeof (Tool).GetMethod("CastTo");

            public static object DynamicCast(object source, Type targetType)
            {
                return CastToInfo.MakeGenericMethod(new[] { targetType }).Invoke(null, new[] { source });
            }
    }

then you can call it:

    var r = Tool.DynamicCast(myinstance, typeof (MyClass));
Overshine answered 17/10, 2018 at 20:40 Comment(0)
P
-1
public bool TryCast<T>(ref T t, object o)
{
    if (
        o == null
        || !typeof(T).IsAssignableFrom(o.GetType())
        )
        return false;
    t = (T)o;
    return true;
}
Pacificia answered 24/1, 2013 at 18:16 Comment(1)
Could you please point out how this answer differs from the other answers and where this solution is appropriate?Candidate
P
-3

even cleaner:

    public static bool TryCast<T>(ref T t, object o)
    {
        if (!(o is T))
        {
            return false;
        }

        t = (T)o;
        return true;
    }
Psychoneurosis answered 6/6, 2015 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.