使用Type变量强制转换变量

时间:2009-06-09 21:39:22

标签: c# reflection types

在C#中,我可以将类型为object的变量转换为类型为T的变量,其中T是在Type变量中定义的吗?

12 个答案:

答案 0 :(得分:162)

当然你可以在这里既简单(假设这是一个T型演员)演员阵容,如果方便的话(假设我们可以把它转换为T)转换:

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

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

修改

评论中的一些人说这个答案没有回答这个问题。但是行(T) Convert.ChangeType(input, typeof(T))提供了解决方案。 Convert.ChangeType方法尝试将任何Object转换为作为第二个参数提供的Type。

例如:

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

// Variable value2 is now an int with a value of 1000
object value2a = Convert.ChangeType(value1, intType);
int value2b = Convert.ChangeType(value1, intType);

// Variable value3 is now an int with a value of 1000
dynamic value3 = Convert.ChangeType(value1, intType);

我已经用泛型编写了答案,因为我想如果你想在没有处理实际类型的情况下将a something强制转换为a something else,这很可能是代码嗅觉的标志。使用适当的接口,99.9%的时间不应该是必需的。在反思中可能有一些边缘情况可能有意义,但我建议避免这些情况。

答案 1 :(得分:92)

其他答案没有提及&#34;动态&#34;类型。所以要再添加一个答案,你可以使用&#34; dynamic&#34;用于存储生成的对象的类型,而不必使用静态类型转换转换的对象。

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

请记住,使用&#34; dynamic&#34;编译器绕过静态类型检查,如果你不小心,可能会引入可能的运行时错误。

答案 2 :(得分:19)

这是我的方法来转换对象而不是通用类型变量,而不是动态System.Type

我在运行时使用类型为System.Linq.Expressions的{​​{1}}创建一个lambda表达式,它将其输入解包,执行所需的类型转换,然后将结果装箱。不仅需要一个新的类型,而且还需要用于获取的类型(因为取消装箱步骤)。创建这些表达式非常耗时,因为反射,编译和动态方法构建都是在幕后完成的。幸运的是,一旦创建了表达式,就可以重复调用表达式而不会产生高额开销,因此我会缓存每个表达式。

Func<object, object>

请注意,这不是魔法。转换不会出现在代码中,就像使用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); } 关键字一样,只会转换对象的基础数据。在编译时,我们仍然需要精心确定我们的对象可能是什么类型,使得这个解决方案不切实际。我把它写成一个hack来调用由任意类型定义的转换操作符,但也许有人可以找到更好的用例。

答案 3 :(得分:7)

为了简单起见,将装箱和拆箱放在一边,在继承层次结构中进行转换时没有涉及特定的运行时操作。这主要是编译时间的事情。从本质上讲,强制转换告诉编译器将变量的值视为另一种类型。

演员表演后你能做些什么?你不知道类型,所以你将无法调用任何方法。你不能做任何特别的事情。具体来说,只有在编译时知道可能的类型,手动编译并使用if语句单独处理每个案例时,它才有用:

if (type == typeof(int)) {
    int x = (int)obj;
    DoSomethingWithInt(x);
} else if (type == typeof(string)) {
    string s = (string)obj;
    DoSomethingWithString(s);
} // ...

答案 4 :(得分:6)

你怎么能这样做?你需要一个T类型的变量或字段,你可以在演员之后存储对象,但如果你只在运行时知道T,你怎么能有这样的变量或字段呢?所以,不,这是不可能的。

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?

答案 5 :(得分:2)

当涉及到枚举类型时:

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

        return null;
    }

您将这样称呼它:

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

对于通过int值获取几种枚举类型的Description属性值的情况,这对我来说至关重要:

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();
    }

然后:

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

或者(更好的方法),这种转换看起来像这样:

 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));
    }

答案 6 :(得分:0)

在使用Zyphrax的答案时,除了找不到任何解决方法之外,“对象必须实现IConvertible”异常(实现接口除外)。我尝试了一些非常规的方法并针对我的情况进行了工作。

使用Newtonsoft.Json nuget软件包...

var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);

答案 7 :(得分:0)

H,问题在于您没有T。

您只有一个Type变量。

向MS提示,如果您可以执行

之类的操作

TryCast<typeof(MyClass)>

如果能解决我们所有的问题。

答案 8 :(得分:0)

我永远无法理解为什么您需要高达50的声誉才能发表评论,但我只能说@Curt答案正是我一直在寻找的东西,希望其他人也可以。

在我的示例中,我有一个ActionFilterAttribute用来更新json补丁文档的值。我不是补丁文档的T模型,我不得不将其序列化和反序列化为一个普通的JsonPatchDocument,对其进行修改,然后因为我有了类型,所以再次对其进行序列化和反序列化为该类型。

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 );

答案 9 :(得分:-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;
}

答案 10 :(得分:-2)

更干净:

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

        t = (T)o;
        return true;
    }

答案 11 :(得分:-2)

如果需要在运行时强制转换对象而不知道目标类型,则可以使用反射来创建动态转换器。

这是简化版本(没有缓存生成的方法):

    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 });
            }
    }

然后您可以调用它:

    var r = Tool.DynamicCast(myinstance, typeof (MyClass));