使用Type变量强制转换变量

the*_*rrs 256 c# reflection types

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

Zyp*_*rax 185

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

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

public T ConvertExamp1<T>(object input) {
    return (T) Convert.ChangeType(input, typeof(T));
}
Run Code Online (Sandbox Code Playgroud)

编辑:

评论中的一些人说这个答案没有回答这个问题.但该线(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);
Run Code Online (Sandbox Code Playgroud)

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

  • 我不知道这对OP有何帮助.她有一个类型变量,而不是`T`. (134认同)
  • @Zyphrax,不,它还需要一个不可用的强制转换为"T". (55认同)
  • @nawfal,基本上是`Convert.ChangeType(input,typeof(T));`给出解决方案.您可以使用现有的类型变量轻松替换`typeof(T)`.更好的解决方案(如果可能的话)是一起防止动态类型. (10认同)
  • 这是如何解决这个问题的?我有同样的问题,我没有通用<T>.我只有一个类型变量. (8认同)
  • ConvertExamp1对我来说很棒.谢谢Zyphrax! (3认同)
  • 我知道结果对象实际上是`T`类型,但你仍然只得到一个`object`作为参考.嗯,我发现这个问题很有趣,前提是OP只有`Type`变量而没有其他信息.好像方法签名是`转换(对象源,类型目的地)`:)尽管如此我得到了你的观点 (3认同)
  • 好吧,我想知道是否有针对这个特定场景的解决方案,无论有人认为它是好代码还是坏代码,但这并没有回答问题:) (3认同)
  • `Convert.ChangeType(value, type)` 中使用的类型必须实现 `IConvertible`,否则会抛出 `System.InvalidCastException`。 (3认同)
  • 作为这很有用的示例,我有一个存储在 SharePoint 工作项队列中的序列化数据列表。我需要将各种工作类型动态反序列化为具体对象,并且直到运行时我才知道我需要哪种类型。 (2认同)
  • @JimYarbro 很公平,Sharepoint 通常是规则的例外;) (2认同)
  • 据我所知,Zyphrax只有在开发时就知道类型,您的解决方案才有效。可以这么说,我不知道如何将其用于“动态”区分。也就是说,它不能解决需要转换为从变量检索的类型而不是进行硬编码的类型的问题。 (2认同)
  • @flip您的ICollector界面已经可以解决这个问题吗?您可以使用诸如System.Reflection.Assembly.GetExecutingAssembly()。CreateInstance(...)之类的东西来创建一个动态收集器,然后将其作为ICollector传递给它。无需将其转换为MySqlCollector或PostgressCollector。 (2认同)

mau*_*k13 103

其他答案没有提到"动态"类型.因此,要再添加一个答案,可以使用"动态"类型来存储生成的对象,而无需使用静态类型转换转换对象.

dynamic changedObj = Convert.ChangeType(obj, typeVar);
changedObj.Method();
Run Code Online (Sandbox Code Playgroud)

请记住,使用"动态"编译器会绕过静态类型检查,如果不小心,可能会引入可能的运行时错误.

  • 这是正确的答案.没有动态关键字typeof(changedObj)就是"对象".使用dynamic关键字,它可以完美地工作,typeof(changedObject)正确地反映了与typeVar相同的类型.此外,如果你不知道类型,你不需要(T)施放你不能做的. (16认同)
  • 使用此解决方案时,出现了“对象必须实现IConvertible”异常。有什么帮助吗? (2认同)
  • 怎么会有这个答案呢?99.99% 的类型没有实现 IConvertible,因此在 99.99% 的情况下它不起作用。 (2认同)

bal*_*age 19

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

我在运行时使用System.Linq.Expressions类型的方法创建一个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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这不是魔术.代码中不会发生转换,就像dynamic关键字一样,只转换对象的基础数据.在编译时,我们仍然需要精心确定我们的对象可能是什么类型,使得这个解决方案不切实际.我把它写成一个hack来调用由任意类型定义的转换运算符,但也许有人可以找到更好的用例.

  • 对我而言,这与Zyphrax的答案一样存在问题.我无法在返回的对象上调用方法,因为它仍然是"对象"类型.无论我使用他的方法(下面的"a")还是你的方法(下面的"b"),我都会在(t)演员上得到同样的错误 - "'t'是一个变量,但是它像一个类型一样使用."Type t = typeof(MyGeneric <>).MakeGenericType(obj.OutputType); var a =(t)Convert.ChangeType(obj,t); var b =(t)Caster.Cast(t,obj);` (3认同)
  • 需要```使用System.Linq.Expressions;``` (2认同)

Meh*_*ari 8

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

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

if (type == typeof(int)) {
    int x = (int)obj;
    DoSomethingWithInt(x);
} else if (type == typeof(string)) {
    string s = (string)obj;
    DoSomethingWithString(s);
} // ...
Run Code Online (Sandbox Code Playgroud)

  • 你的答案是好的,但只是为了挑剔,我注意到演员阵容永远不会影响_variables_.将_variable_转换为另一种类型的变量是不合法的; 变量类型在C#中是不变的.您只能将存储在变量中的_value_转换为其他类型. (4认同)

小智 7

在使用 Zyphrax 的答案时没有找到任何解决“对象必须实现 IConvertible”异常的方法(实现接口除外)。我尝试了一些非常规的方法并适合我的情况。

使用 Newtonsoft.Json nuget 包...

var castedObject = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(myObject), myType);
Run Code Online (Sandbox Code Playgroud)


Dan*_*ner 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?
Run Code Online (Sandbox Code Playgroud)

  • 幸运的是,这不是正确的答案.请参阅maulik13的回答. (7认同)
  • 如果您使用泛型类,它定义了返回值为T的方法,则可能需要这样做.例如,将字符串解析为T的实例并返回该实例. (3认同)
  • 你在天堂的名字里找到`对象`的`CastTo`方法? (3认同)