2016-02-08 7 views
4

Я создаю тип во время выполнения, используя Reflection.Emit. Проблема в том, что всякий раз, когда я создаю экземпляр нового типа, я должен использовать object или dynamic, потому что этот тип неизвестен во время компиляции. Это отлично работает, за исключением тех случаев, когда я хотел бы, чтобы другой тип неявно приводил к новому типу во время назначения. Переменная счастливо принимает новое значение и соответствует соответствующему типу, не пытаясь применить его к текущему типу.Можно ли использовать неявные приведения типов, созданных во время выполнения в C#?

Есть ли способ создать переменную только что созданного типа, которая позволит использовать неявное литье? Я с удовольствием откажусь от проверки времени компиляции, но я бы хотел, чтобы эти приведения, по крайней мере, были предприняты во время выполнения.

Edit:

Вот пример, чтобы сделать его более ясным. Это то, что происходит, когда вы знаете, типа во время компиляции:

MyClass a; 
//this calls the implicit cast operator and 'a' stays of the same type 
a = 5; 

и это то, что произойдет, если вы этого не сделаете:

Type t = CreateTypeUsingTypeBuilder(); 
object a = Activator.CreateInstance(t); 
//this does not call the implicit cast operator and 'a' just becomes in integer 
a = 5; 

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

+8

Это действительно неясно, что вы имеете в виду, я боюсь, но если тип не существует во время компиляции, трудно понять, как вы ожидаете, что компилятор узнает, что будет доступно неявное преобразование. Если бы вы могли дать нам конкретный пример того, что вы пытаетесь сделать, это действительно поможет. –

+0

Неявное кастинг требует знания во время компиляции некоторого типа исходного объекта (чтобы определить, для какого оператора неявного преобразования нужно позвонить). Вы можете реализовать интерфейс; или использовать динамические и предоставлять необходимые имплицитные операторы преобразования. – Richard

+0

Вероятно, вы хотите определить интерфейс, который описывает, какие свойства и методы имеет этот испущенный объект, который вы хотите использовать в приложении. Извлеките свой код, а затем передайте результат в этот интерфейс. Очевидно, что класс, который вы создаете, должен реализовать интерфейс. Но это даст вам хорошее время. – Will

ответ

2

Чтобы понять, почему это невозможно, по крайней мере, не напрямую, нужно понять, как работают неявные операторы преобразования.

Когда вы пишете что-то вроде этого

MyNumericType x = new MyNumericType(123); 
double y = x; 

компилятор понимает, что x и y бывают разных типов, и ищет MyNumericType, чтобы увидеть, если есть неявный оператор преобразования определяется:

public static implicit operator double(MyNumericType n) { 
    return n.doubleValue; 
} 

Как только оператор найден, компилятор вызывает его, как если бы это был обычный метод static (which it is).

Когда вы работаете с типами, сгенерированными во время выполнения, вы также должны генерировать преобразование во время выполнения. Например, если вы сделаете это

private static Func<object,object> MakeConverter(Type t1, Type t2) { 
    var p = Expression.Parameter*(typeof(object)); 
    var eFrom = Expression.Convert(p, t1); 
    var eTo = Expression.Convert(eFrom, t2); 
    var res = Expression.Convert(eTo, typeof(object)); 
    var lambda = Expression.Lambda<Func<object,object>>(res, new[] { p }); 
    return (Func<object,object>)lambda.Compile(); 
} 

С помощью этого метода в месте вы можете сделать это:

Type runtimeType1 = ... 
Type runtimeType2 = ... 
var converter = MakeConverter(runtimeType1, runtimeType2); 
object objRuntimeType1 = ... 
object objRuntimeType2 = converter(objRuntimeType1); 
0

Если идея, как я полагаю, в этом контексте, чтобы создать классы-обертки для известных типов во время выполнения, у меня есть несколько идей, которые вы могли бы попробовать.

Одним из них является добавление параметризованного конструктора в тип обертки, который принимает объект обернутого типа в качестве параметра, а затем использует этот объект для инициализации объекта-оболочки (как и в случае с неявным оператором преобразования). Затем, зная, что вы можете использовать, например, целое число в качестве параметра конструктора, вы можете просто сделать это:

Type t = CreateTypeUsingTypeBuilder(); 
object a = Activator.CreateInstance(t, 5); 

Это будет искать тип для конструктора, который может быть вызван с данным объектом. Вы можете получить MissingMethodException, если не найдено подходящего общедоступного конструктора.

Другой идеей является создание интерфейса или абстрактного базового типа для ваших типов, встроенных во время выполнения, что требует, чтобы производные классы применяли какой-то метод преобразования. Когда вы извлекаете свои построенные типы из этого абстрактного класса или заставляете их реализовывать интерфейс, вы можете отбросить объект, созданный с помощью Activator, этому классу или этому интерфейсу, а затем вызвать метод конвертации уже в обычном режиме. Если вы создадите свой общий интерфейс, вы можете иметь несколько различных реализаций преобразования.

public interface IMyWrapper<T> 
{ 
    IMyWrapper<T> Convert(T value); 
} 

Хотя нет никакого способа, чтобы использовать неявный оператор неявно, я думаю, вы могли бы достичь своей конечной цели преобразования целого числа к бортовому типа каким-либо другим способом, в том числе один или другой намекал выше.