Описание преобразования типов данных и пример его использования

Свойства классов данных могут иметь самый различный тип, как стандартный для .Net framework (например, такой как System.Int32 — int в C#, System.String — string в C#), так и нестандартный (какой-либо пользовательский, не .Net-тип).

Значения стандартных типов преобразуются сервисами данных в типы хранилища некоторым предопределённым образом, например, System.Int32 в LONG, System.String в VARCHAR. Однако, сервис данных никак «не знает», каким образом должно преобразовываться значение некоторого пользовательского типа (иначе говоря, какого типа значение в хранилище). Следовательно, значение пользовательского типа должно приводиться к значению стандартного типа .Net и обратно, а со значением стандартного типа сервис данных уже «разберётся».

Как именно такое приведение должно выполняться конкретным сервисом данных, указывается непосредственно пользовательскому типу атрибутом StoreInstancesInTypeAttribute. Параметрами указываются: тип сервиса данных и стандартный тип, к которому должно выполняться приведение.

От пользовательского типа требуется следующее:

  • Поддержка явного (explicit) или неявного (implicit) преобразования к стандартному типу.
  • Поддержка явного (explicit) или неявного (implicit) обратного преобразования от стандартного типа.
  • Перегрузка метода ToString().

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

Пример пользовательского типа

[StoreInstancesInType(typeof(SQLDataService),typeof(decimal)))
public struct Деньги
{
	public class ParameterOutOfRangeException:Exception
	{
			public ParameterOutOfRangeException(){}
	}
	
	private int fieldРубли;
	private int fieldКопейки;
	
	public Деньги(int Руб,int Коп)
	{
			fieldРубли = 0;
			fieldКопейки = 0;
			Рубли = Руб;
			Копейки = Коп;
	}
	
	public int Рубли
	{
			get{return fieldРубли;}
			set
			{
					if (value>=0)
							fieldРубли = value;
			}
	}
	
	public int Копейки
	{
			get {return fieldКопейки;}
			set
			{
					if (value>=0 && value<100)
							fieldКопейки = value;
					else
							throw new ParameterOutOfRangeException();
			}
	}
	
	public static implicit operator decimal(Деньги value)
	{
			return (decimal)value.Рубли+((decimal)value.Копейки)/100;
	}
	
	public static implicit operator Деньги(decimal value)
	{
			return new Деньги((int)value,(int)((value-(int)value)*100));
	}
	
	public override string ToString()
	{
			return Рубли.ToString()+" руб. "+Копейки.ToString()+" коп.";
	}
}

Также доступен пример на GitHub.