将对象转换为仅在运行时已知的类型变量

时间:2018-06-22 14:04:59

标签: c# casting runtime

有人可以帮助我了解为什么以下内容不起作用吗?

void test(int i)
{
    Console.WriteLine("int");
}

void test(String s)
{
    Console.WriteLine("String");
}

void runMe()
{
    object obj = 1;
    Type t = typeof(int);
    test((t)obj);
}

您收到“找不到类型或名称空间名称't'”错误。

有没有办法使这项工作有效?我需要将对象转换为仅在运行时才知道的特定类型,但是我发现的所有选项只是在转换数据,但仍将其存储在对象中。

编辑:添加了一些伪方法以提供更多上下文。

2 个答案:

答案 0 :(得分:2)

看起来您基本上是在尝试执行动态调度。您尝试使用的方式将无法正常工作,因为在使用静态类型时,所有重载解析都是在执行时执行的。

但是,您可以使用dynamic类型的动态类型来代替。此时,将在执行时执行重载解析:

void Test(int i)
{
    Console.WriteLine("int");
}

void Test(String s)
{
    Console.WriteLine("String");
}

void RunMe()
{
    dynamic obj = 1;
    // The right overload is picked at execution time
    Test(obj);
}

这将完成您在问题中显示的内容-但这不一定是最好的方法。如果您可以可能坚持使用静态类型(不使用反射),那么我会这样做。如果您只能处理一组已知的类型,则可能需要保留Dictionary<Type, Action<object>>或类似的内容……尽管随后您需要考虑一些麻烦的事情,例如子类型化等。

如果您要做使用动态类型,我将尝试仅将其用于一小段代码。只要您可以“退出”动态类型,就可以这样做(例如,将动态绑定调用的结果强制转换为其预期的返回类型)。

答案 1 :(得分:0)

这是一个示例,其中有几种方法可以将其组合为一个示例。

第一种方法是重载您的方法以获取受支持的类型(当在编译时知道类型时可以直接调用这些方法),并创建一个具有对象类型参数的通用默认重载方法,该方法在内部检查受支持的类型和调用适当的特定于类型的方法(仅适用于运行时已知的类型)。

第二种方法可以用作第一种方法的扩展,但是您也可以仅实现第二种方法而跳过第一部分。由于您知道运行时开始时的类型,并且预计该类型不会随每次调用更改,因此您可以跳过每次调用的类型检查,而是在加载配置时进行一次检查,然后设置适当的值委托。

尝试:https://dotnetfiddle.net/06JYE1#

using System;

public class Program
{
    public static void Main()
    {       
        var p = new Program();

        object s = "Hi";
        object i = 42;
        object f = 3.14;

        p.Test(s);
        p.Test(i);
        p.Test(f);

        p.SetTestType(GetConfigType());

        p.ConfiguredTest("Hello");
        p.ConfiguredTest(s);
    }

    public static Type GetConfigType() { return typeof(string); }



    Action<object> ConfiguredTest;

    void SetTestType(Type type)
    {
        if (type == typeof(string))
            ConfiguredTest = o => Test((string)o);

        else if (type == typeof(int))
            ConfiguredTest = o => Test((int)o);

        else
            ConfiguredTest = null;
    }

    void Test(object o) // catch-all when type is not known until runtime
    {
        if (ConfiguredTest != null)
        {
            ConfiguredTest(o); // if type is configured, we can skip type checking
        }
        else // if type is not configured, check for supported types
        {
            if (o is string)
                Test((string)o);

            else if (o is int)
                Test((int)o);

            else
                Console.WriteLine("Unsupported type: " + o.GetType());
        }
    }

    void Test(int i) { Console.WriteLine("Int = " + i); }

    void Test(String s) { Console.WriteLine("String = " + s); }

}