创建仅在运行时已知的类型的变量(C#)

时间:2013-05-23 20:10:04

标签: c# generics dynamic reflection

我的问题非常类似于:Cast to type known only at runtime,但是那个问题没有得到真正的回答(它也是在C而不是C#中)。

我正在写一些东西来控制一些硬件,并且根据给定的硬件配置,我必须使用“byte”或“UInt32”类型进行一些按位算术。位算术代码很长但在32位和8位情况下相同,唯一的区别是某些循环的长度(32或8)。

我目前的解决方案是使用一个开关,这意味着我在一个巨大的if语句中有相同代码的两个副本。

另一种解决方案是使用数组或0和1而不是UInt32或字节来执行按位操作,然后在结尾处转换为UInt32或字节。

我最感兴趣的最后一个解决方案是动态选择我将在运行时使用的类型。这是我想要的伪代码:

System.Type MyType;    
if (something)
    MyType=type1;
else
    MyType=somethingElse;

myType someVariable; //Create a variable of type myType. This line will give an 
                     //error
someVariable=(myType) otherVariable //do an example typecast with the 
                                    //runtime-determined type

我已经四处搜寻,知道答案可能与泛型和反射有关,但我无法弄清楚如何做到这一点。

5 个答案:

答案 0 :(得分:1)

您可以考虑使用BitArray - 您可以从字节或uint32初始化它,执行按位操作,然后在最后将其转换回来,例如。

    object value;
    bool isByte = value is byte;
    BitArray ba = isByte
        ? new BitArray(new byte[] { (byte)value })
        : new BitArray(BitConverter.GetBytes((unint32)value));
   ...

答案 1 :(得分:1)

我可能会创建一个抽象类,类似于HardwareConfigBase,它包含循环代码以及循环的大小。然后有2个扩展该基类的子类。

public abstract class HardwareConfigBase
{
    protected int TimesToLoop;
    public byte[] Data = new byte[32 * 8]; //Size of UInt, but still works for 8bit byte

    public void MyLoopCode
    {
        for(int i = 0; i < TimesToLoop; i++)
        {
            //Do whatever
        }
    }
}

public class ByteHardwareConfig
{
    public ByteHardwareConfig
    {
        TimesToLoop = 8;
    }
}

public class UIntHardwareConfig
{
    public UIntHardwareConfig
    {
         TimesToLoop = 32;
    }
}

public void Main()
{
    var myHardwareConfig = new ByteHardwareConfig(); //Could also be UInt
    //Do some more initialization and fill the Data property.
    myHardwareConfig.MyLoopCode();
}

答案 2 :(得分:0)

您可以使用Activator.CreateInstance()在运行时创建类型的实例,如下所示:

object myInstance = Activator.CreateInstance(MyType);

然后,请参阅this question,了解如何仅使用运行时已知的类型在运行时进行类型转换。

public static dynamic Convert(dynamic source, Type dest) {
    return Convert.ChangeType(source, dest);
}

myInstance = Convert(myInstance, MyType);
// will result in myInstance being of type MyType.

答案 3 :(得分:0)

答案非常简单。您不需要在运行时转换或转换任何变量,以便能够在运行时修改 uint byte 类型。以下三个定义就足够了。

第一个类定义是 Provider 类,它定义了两个方法,每个方法用于修改 uint byte 类型的变量。务必将修改逻辑放在方法中。

class Provider
{
    public uint GetResult(uint c)
    {
        return c;
    }

    public byte GetResult(byte c)
    {
        return c;
    }
}

下一个类将根据您提供的参数类型调用前一个类定义中的相应方法。

class Execute
{
    public object GetResult(object source)
    {
        var provider = new Provider();

        return provider.GetType()
                       .GetMethods()
                       .Where(x => x.Name == "GetResult" && x.ReturnType == source.GetType())
                       .First()
                       .Invoke(provider, new object[] { source });
    }
}

此处的最后一个定义是简单地测试此设置的工作原理。您可以看到我们同时拥有字节 uint 类型。将它们传递给 GetResult(object)方法会产生预期的结果,如您所见,底层系统类型也是预期的。

class Program
{
    static void Main()
    {
        uint u = 1;
        byte b = 2;

        var result1 = new Execute().GetResult(u);
        var result2 = new Execute().GetResult(b);

        sc.WriteLine(result1 + " " + result1.GetType().UnderlyingSystemType);
        sc.WriteLine(result2 + " " + result2.GetType().UnderlyingSystemType);

        sc.Read();
    }
}

答案 4 :(得分:-1)

尝试在C#中使用dynamic关键字。

dynamic myType;
if (a) {
    myType = new type1();
} else {
    myType = new type2();
}