2013-05-23 3 views
2

Мой вопрос очень похож на: Cast to type known only at runtime, однако на него не ответил (он также находится на C, а не на C#).Создайте переменную типа, известного только во время выполнения (C#)

Я пишу что-то для управления некоторым оборудованием, и в зависимости от данной конфигурации оборудования мне нужно выполнить некоторую побитную арифметику с типом «байт» или «UInt32». Битовый арифметический код длинный, но идентичный в 32-битном и 8-битном случае, с той лишь разницей, что длина определенных петель (32 или 8).

Мое настоящее решение заключается в использовании переключателя, что означает, что у меня есть почти две копии одного и того же кода в гигантском выражении if.

Альтернативным решением является использование массива или 0s и 1s, а не 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 

Я искал вокруг, чтобы знать, что ответ может иметь что-то делать с обобщениями и отражением, но я не могу понять, как сделать это точно.

+1

Как только вы создали значение, что вы собираетесь с ним делать? Как вы собираетесь делать на нем арифметические операции? –

+0

Что вы планируете делать с помощью someVariable? Поскольку неизвестно, какой тип это будет до выполнения, вам будет сложно писать код против него. Специфика того, что вам нужно сделать с этим, будет определять, как заставить систему типов хорошо играть ... –

+0

Если единственное различие - это количество циклов, почему бы просто не понять это? for (int i = 0; i <(byteConfig? 8: 32); i ++)? –

ответ

-1

Попробуйте использовать ключевое слово dynamic на C#.

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

-1: Тип 'myType' уже известен: это' Type'. Это не проблема. –

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. 
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

я бы, вероятно, создать абстрактный класс, что-то вроде 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(); 
} 
0

Ответ довольно довольно простой. Вам не нужно включать или преобразовывать любые переменные во время выполнения, чтобы иметь возможность изменять uint или байт типов во время выполнения. Достаточно трех следующих определений.

Определением первого класса является провайдером класса, который определяет два метода, каждый из которых либо модифицировать переменную UINT или байт типа. Обязательно поместите свою модифицирующую логику в методы.

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(); 
    } 
} 
Смежные вопросы