C#:如何使用Type执行'as'操作

时间:2011-09-21 18:37:00

标签: c# .net casting type-conversion

我想测试一个给定的object是否可以转换为给定的Type

在这种情况下,我有一个对象,而Type代表我想要将它投射到的类型:

public function FooBar(..., object data, Type expected) {
    ...
    var unboxedData = ?
    if (unboxedData == null) {
       ....
    }
    ...
}

如何将data投射到type代表的类型?

基本上,我想这样做:

    var unboxedData = data as Type;

...但当然您不能将Typeas声明一起使用,那么我该怎么办?

6 个答案:

答案 0 :(得分:6)

编辑2:我会说没有反思或泛型,这是不可能的。使用反射,您没有编译时检查,必须使用反射(或dynamic)来进一步调用对象的方法/属性。使用泛型,您不能使用Type对象单独使用。随便挑选。是否可以重构您的调用代码以允许泛型?


如果允许,可以使用通用方法更轻松地处理:

public resultType FooBar<T>(..., object data) {
    ...
    T unboxedData = (T)data;
    ...
}

修改:如果您包含data as T的通用类型约束,则可以使用where T : class

public something FooBar<T>(..., object data)
    where T : class
{
    ...
    T unboxedData = data as T;
    if (unboxedData == null) {
        ...
    }
    ...
}

答案 1 :(得分:3)

  

...但当然你不能使用带有as语句的Type,所以我该怎么办?

Morre重要的是,你不能以这种方式使用var。所以这里没有什么可以获得的。

如果是正确的

类型,您可以测试
 if (expected.IsInstanceOfType(data))

但是你仍然无法编写任何合适的代码来访问data上的属性或方法。

答案 2 :(得分:2)

C#快速提供as关键字 在运行时确定给定类型是否与另一个类型兼容。使用as关键字时,可以通过检查null返回值来确定兼容性。请考虑以下事项:

Hexagon hex2 = frank as Hexagon;

if (hex2 == null)
    Console.WriteLine("Sorry, frank is not a Hexagon...");

除了as关键字之外,C#语言还提供了is关键字来确定两个项是否兼容。但是,与as关键字不同,如果类型不兼容,则is关键字返回false,而不是null引用。

if (emp is SalesPerson)
{
    Console.WriteLine("{0} made {1} sale(s)!", emp.Name, 
                                              ((SalesPerson)emp).SalesNumber);
}

答案 3 :(得分:1)

if (data.GetType() == t || data.GetType().IsSubclassOf(t))
{
//do your thing
}

应该告诉你它是否完全或是它的子类(因此它可以被投入其中)。

答案 4 :(得分:1)

这非常棘手。问题是var并不代表“变体”。一旦可以从表达式推断出类型信息,它就更像是临时占位符,C#用实际类型填充。 unboxedData仍然是一个强类型变量。它只是编译器试图找出类型而不是你明确指定它。值得注意的是,键入仍然在编译时发生,而不是运行时。

如果要在运行时动态转换对象,则无法使用var或任何其他具体类型说明符。

您的选择仅限于两种可能的声明之一:

  • 物体
  • 动态

根据我想要用unboxedData做的想法,我怀疑dynamic是你要去的路线,因为它可以让你调用任何方法目标Type

所以这就是我想出来的。

public void FooBar(object value, Type expected)
{
  dynamic unboxedData = expected.FromObject(value);
  unboxedData.CallSomeMethodDefinedInTheTargetType(); // This will work.
}

这需要以下扩展方法。

public static class TypeExtension
{
    public static object FromObject(this Type target, object value)
    {
        var convertable = value as IConvertible;
        if (convertable != null)
        {
            return convertable.ToType(target, null);
        }
        Type type = value.GetType();
        if (target.IsAssignableFrom(type))
        {
            return value;
        }
        MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
        foreach (MethodInfo mi in methods)
        {
            if (mi.ReturnType == target)
            {
                try
                {
                    return mi.Invoke(null, new object[] { value });
                }
                catch (TargetInvocationException caught)
                {
                    if (caught.InnerException != null)
                    {
                        throw caught.InnerException;
                    }
                    throw;
                }
            }
        }
        throw new InvalidCastException();
    }
}

如果满足下列条件之一,演员阵容将有效。

  • 要转换的值实现IConvertible并具有指向目标类型的转换路径。
  • 要转换的值是目标类型的子类。
  • 要转换的值在其类声明中定义explicit conversion operator

答案 5 :(得分:0)

好吧,环顾四周我发现了什么... How to check if implicit or explicit cast exists?

要小心,我没有给它太多的测试,但一眼就看出它很有希望。一个很大的负面因素是,如果它无法转换,它会抛出异常:

    static bool isConvertableTo(object o, Type t)
    {
        try
        {
            var expr = Expression.Constant(o);
            var res = Expression.Convert(expr, t);
            return true;
        }
        catch { }
        return false;
    }

使用相同方法的另一个有用链接:Checking if a type supports an implicit or explicit type conversion to another type with .NET