Расширение системы типов .NET, так что в некоторых случаях компилятор обеспечивает семантическое значение примитивных значений - PullRequest
6 голосов
/ 31 мая 2010

Я сейчас работаю над разработкой системы, которая имеет дело со множеством преобразований между семантически различными значениями, имеющими один и тот же примитивный тип .NET (double / string / int). Это означает, что можно запутаться в том, какой «семантический тип» вы используете, либо не конвертируя, ни конвертируя слишком много раз. В идеале я бы хотел, чтобы компилятор выдавал предупреждение / ошибку, если я пытаюсь использовать значение, которое не имеет смысла семантически.

Некоторые примеры, чтобы указать, что я имею в виду:

  • Углы могут быть в градусах или радианах, но оба представлены как double.
  • Позиции вектора могут быть в локальных / глобальных координатах, но оба они представлены в виде Vector3D struct.
  • Представьте себе библиотеку SQL, которая принимает различные параметры запроса в виде строк. Было бы хорошо иметь способ принудительно разрешить передачу только чистых строк во время выполнения, и единственный способ получить чистую строку - пройти через некоторые атаки SQL-инъекций, предотвращающие логику.

Я полагаю, что F # имеет решение во время компиляции для этого (называемое единицами измерения). Я хотел бы сделать нечто подобное в C #, хотя мне не нужен анализ измерений, который предлагает единицы измерения в F #.

Я считаю, что C ++ мог бы добиться этого, используя typedef (хотя я не эксперт по C ++).

Очевидное решение состоит в том, чтобы обернуть double / string / what в новый тип, чтобы дать ему информацию о типе, необходимую компилятору. Мне любопытно, если у кого-нибудь есть альтернативное решение. Если вы думаете, что перенос - это единственный / лучший способ, то, пожалуйста, рассмотрите некоторые недостатки шаблона (и любые недостатки, о которых я тоже не упомянул). Меня особенно беспокоит производительность абстрактных примитивных числовых типов на моем вычисления во время выполнения, поэтому любое решение, которое я приду, должно быть легким как с точки зрения распределения памяти, так и с точки зрения распределения вызовов.

Ответы [ 3 ]

3 голосов
/ 01 июня 2010

Полагаю, вы могли бы создать две разные структуры для проверки типов. В следующем коде я добавил неявное приведение от радианов к удвоению и явное приведение от разложения к радианам. Вы можете использовать любой набор неявных и явных операторов, которые вам нравятся, но я думаю, что те, которые я определил здесь, будут работать хорошо, поскольку структура Radians может быть передана непосредственно в Math функции.

public struct Degrees
{
  private double m_Value;

  public static explicit operator Radians(Degrees rhs)
  {
    return rhs.m_Value * (Math.Pi / 180);
  }
}

public struct Radians
{
  private double m_Value;

  public static implicit operator double(Radians rhs)
  {
    return rhs.m_Value;    
  }
}
3 голосов
/ 31 мая 2010

Мне действительно интересно, как компилятор выдает предупреждение, когда вы смешиваете радианы и градусы. Они оба двойные? Вы находитесь в мире ООП, поэтому вы должны идти по этому пути. Два предложения:

  1. Используйте только одну единицу внутри, я думаю, радианы лучше. Затем конвертируйте только на входе / выходе. \
  2. Создание структур Degree, Radian и определение правил конверсий. Или создайте класс «Угол» и держите там всю информацию о единицах и преобразованиях.
0 голосов
/ 31 мая 2010

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

...