【问题标题】:Create a variable of a type only known at runtime (C#)创建仅在运行时知道的类型的变量 (C#)
【发布时间】:2013-05-19 08:21:53
【问题描述】:

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

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

我目前的解决方案是使用 switch,这意味着我在一个巨大的 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

我四处搜索知道答案可能与泛型和反射有关,但我不知道该怎么做。

【问题讨论】:

  • 一旦你创造了价值,你打算用它做什么?你打算如何对其进行算术运算?
  • 你打算用 someVariable 做什么?由于直到运行时才知道它是什么类型,因此您将很难针对它编写代码。你需要做什么的细节将决定如何让类型系统很好地配合......
  • 如果唯一的区别是循环的数量,为什么不弄清楚呢? for (int i = 0; i

标签: c# generics dynamic reflection


【解决方案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));
   ...

【讨论】:

    【解决方案2】:

    我可能会创建一个抽象类,例如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();
    }
    

    【讨论】:

      【解决方案3】:

      您可以在运行时使用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.
      

      【讨论】:

        【解决方案4】:

        答案相当简单。您无需在运行时强制转换或转换任何变量即可在运行时修改 uintbyte 类型。以下三个定义就足够了。

        第一个类定义是 Provider 类,它定义了两个方法,每个方法修改 uintbyte 类型的变量。请务必将修改逻辑放入方法中。

        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 });
            }
        }
        

        最后一个定义是为了简单地测试这个设置是如何工作的。你可以看到我们有一个 byte 和一个 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();
            }
        }
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • -1:myType 的类型已知:它是Type。没有问题。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-17
          相关资源
          最近更新 更多