9

Учитывая этот класс с неявным оператором литом:Есть ли способ сделать динамическое неявное литье типов в C#?

public class MyDateTime 
{ 
    public static implicit operator MyDateTime(System.Int64 encoded) 
    { 
     return new MyDateTime(encoded); 
    } 

    public MyDateTime(System.Int64 encoded) 
    { 
     _encoded = encoded; 
    } 
    System.Int64 _encoded; 
} 

теперь я могу сделать следующее:

long a = 5; 
MyDateTime b = a; 

, но не ниже:

long f = 5; 
object g = f; 
MyDateTime h = g; 

Это дает время компиляции:

Невозможно неявно преобразовать тип 'object' в 'MyDateTime'.

Имеет смысл для меня.

Теперь я могу изменить предыдущий пример следующим образом:

long f = 5; 
object g = f; 
MyDateTime h = (MyDateTime)g; 

Это нормально компилируется. Теперь я получаю время выполнения InvalidCastException:

Невозможно лить объект типа 'System.Int64' для ввода MyDateTime '.

Это говорит о том, что C# неявные операторы литья применяются только во время компиляции и не применяются, когда среда выполнения .NET пытается динамически отличать объект от другого типа.

Мои вопросы:

  1. я правильно?
  2. Есть ли другой способ сделать это?

Кстати, полное приложение является то, что я использую Delegate.DynamicInvoke() для вызова функции, которая принимает параметр MyDateTime и тип аргумента я передаю к DynamicInvoke длинный.

ответ

13

Я правильно?

Да, да. Чтобы быть ничтожным, вы должны сказать «пользовательское неявное преобразование», а не «неявное приведение» - приведение (почти) всегда явное. Но ваш вывод о том, что разрешение перегрузки выбирает, какое пользовательское преобразование вызывать во время компиляции, а не во время выполнения.

Есть ли другой способ сделать это?

Да. В C# 4, если вы наберете свой «объект» как «динамический», тогда мы снова запустим компилятор во время выполнения и повторно выполним весь анализ операндов , как если бы их типы времени компиляции были текущими типами времени выполнения.Как вы можете себе представить, это не дешево, хотя мы очень умны в кэшировании и повторном использовании результатов, если вы сделаете это в плотном цикле.

+0

Просто из любопытства, каковы причины, по которым операторы не ведут себя как методы во время выполнения? Учитывая ваш ответ, кажется, что они всего лишь синтаксический сахар и не намного больше. На мой взгляд, это сделает C# еще более мощным, если такие операторы будут продвигаться как первоклассный член любого типа (что означает, что они становятся частью всего другого объектно-ориентированного добра, такого как наследование, переопределение и взаимодействие). Посредством использования этих средств во время выполнения по умолчанию подразумеваются значительные изменения в дизайне и внедрении языка? – MarioDS

+1

@MDeSchaepmeester: Вы правы, что здесь есть немного разъединения. Сравните дизайн int с десятичным, например. Вы можете сказать 'Func add = decimal.Add;', но нет способа сделать то же самое для int; вы должны сказать 'Func add = (x, y) => x + y'. Было бы неплохо, если бы все встроенные типы были разработаны как Decimal, а затем среда выполнения или компилятор могли бы выбрать, чтобы снизить их до более фундаментальных операций по соображениям производительности. Но такая последовательность последовательно вытекает из «функционального» мышления. –

+1

@MDeSchaepmeester: Я подозреваю, что оригинальные дизайнеры среды выполнения просто не думали об этом объединении функциональной абстракции при проектировании системы типов и операций над встроенными типами. И, конечно, также нечетно, что в десятичной системе есть как оператор +, так и метод Add. И даже не заставляйте меня начинать с дюжины способов представления операции равенства! Это действительно беспорядок. В следующий раз, когда вы создадите структуру с нуля, сначала получите это. –

-2

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

long f = 5; 
object g = f; 
MyDateTime h = g as MyDateTime; 
+0

Он будет работать отлично в том смысле, что он не будет 'InvalidCastException', однако' h' будет 'null', чего не хочет или ожидает OP. – MarioDS