C# 使用类型变量强制转换变量

C# 使用类型变量强制转换变量,c#,reflection,types,C#,Reflection,Types,在C#中,我是否可以将object类型的变量强制转换为T类型的变量,而T是在类型变量中定义的?为了简单起见,将装箱和取消装箱放在一边,沿继承层次结构强制转换时不涉及任何特定的运行时操作。这主要是编译时的事情。本质上,强制转换告诉编译器将变量的值视为另一种类型 剧组结束后你能做什么?您不知道类型,因此无法对其调用任何方法。你不会有什么特别的事情可以做。具体来说,只有在编译时知道可能的类型、手动强制转换并使用if语句分别处理每种情况时,它才有用: if (type == typeof(int)) {

在C#中,我是否可以将object类型的变量强制转换为T类型的变量,而T是在类型变量中定义的?

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

剧组结束后你能做什么?您不知道类型,因此无法对其调用任何方法。你不会有什么特别的事情可以做。具体来说,只有在编译时知道可能的类型、手动强制转换并使用
if
语句分别处理每种情况时,它才有用:

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

你怎么能这么做?您需要一个类型为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?

以下是强制转换和转换的示例:

using System;

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

public T ConvertObject<T>(object input) {
    return (T) Convert.ChangeType(input, typeof(T));
}
我已经用泛型写了答案,因为我认为当您想在不处理实际类型的情况下将
a something
转换为
a something
时,这很可能是代码气味的迹象。99.9%的情况下不需要使用适当的接口。当涉及到反射时,可能有一些边缘情况是有意义的,但我建议避免这些情况

编辑2:

一些额外的提示:

  • 尽量保持代码的类型安全。如果编译器不知道类型,则无法检查代码是否正确,自动完成之类的操作将无法工作。简单地说:如果您不能在编译时预测类型,那么编译器将如何预测
  • 如果您使用的是类,则可以将值强制转换到该接口。否则,考虑创建自己的接口并让类实现该接口。
  • 如果您使用的是动态导入的外部库,那么还要检查公共接口。否则,请考虑创建实现接口的小包装类。
  • 如果要调用对象,但不关心类型,则将值存储在
    对象
    或变量中
  • 可以很好地创建适用于许多不同类型的可重用代码,而不必知道所涉及的确切类型
  • 如果你陷入困境,那么考虑一个不同的方法或代码重构。你的代码真的必须是动态的吗?它是否必须考虑到存在的任何类型
公共bool TryCast(参考T,对象o)
{
如果(
o==null
||!typeof(T).IsAssignableFrom(o.GetType())
)
返回false;
t=(t)o;
返回true;
}

其他答案没有提到“动态”类型。所以,若要再添加一个答案,您可以使用“动态”类型来存储生成的对象,而不必使用静态类型强制转换转换的对象

dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
请记住,使用“动态”编译器会绕过静态类型检查,如果不小心,可能会导致运行时错误

此外,还假设obj是typeVar类型的实例或可转换为该类型。

甚至:

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

        t = (T)o;
        return true;
    }
公共静态bool TryCast(参考T,对象o)
{
如果(!(o是T))
{
返回false;
}
t=(t)o;
返回true;
}

以下是我的方法,用于强制转换对象,但不是将其转换为泛型类型变量,而是转换为
系统。动态转换类型

我在运行时使用类型为
Func
System.Linq.Expressions
创建一个lambda表达式,该表达式取消其输入的装箱,执行所需的类型转换,然后给出装箱的结果。不仅对于所有被强制转换到的类型,而且对于被强制转换的类型(因为取消装箱步骤),都需要一个新的类型。创建这些表达式非常耗时,因为反射、编译和动态方法构建都是在后台完成的。幸运的是,一旦创建了表达式,就可以重复调用,而且不会有太大的开销,所以我会缓存每个表达式

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);
}
private static Func MakeCastDelegate(键入from,键入to)
{
var p=Expression.Parameter(typeof(object));//不内联
返回表达式.Lambda(
Expression.Convert(Expression.ConvertChecked(Expression.Convert(p,from),to),typeof(object)),
p) .Compile();
}
专用静态只读字典缓存
=新字典();
公共静态函数GetCastDelegate(类型从,类型到)
{
锁(CastCache)
{
var key=新元组(从、到);
Func cast_代表;
if(!CastCache.TryGetValue(键,out cast_委托))
{
cast_delegate=MakeCastDelegate(从,到);
添加(键,强制转换委托);
}
返回cast_代表;
}
}
公共静态对象强制转换(类型t,对象o)
{
返回GetCastDelegate(o.GetType(),t).Invoke(o);
}

请注意,这不是魔术。与使用
dynamic
关键字一样,转换不会在代码中发生,只有对象的底层数据被转换。在编译时,我们仍然需要费劲地弄清楚对象可能是什么类型,这使得这个解决方案不切实际。我写这篇文章是为了攻击调用由任意类型定义的转换运算符,但也许有人可以找到更好的用例。

当转换为枚举类型时:

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);
 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));
    }
在通过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));
或者(更好的方法),此类铸造可以如下所示:

var enumValue = GetEnum(typeof(YourEnum), foo);
 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));
    }
private static T GetEnum(int v),其中T:struct,IConvertible
{
if(类型(T).IsEnum)
如果(枚举已定义(类型(T),v))
{
    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));
var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);
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 );