Я создал собственную (только для чтения) структуру для инкапсуляции десятичной дроби. Я использую всюду структуру, в том числе общедоступный API, используемый различными языками программирования, и поэтому хотел бы избежать раскрытия десятичных типов данных.
Здесь показаны соответствующие части структуры:
[ProtoContract(SkipConstructor = false, ImplicitFields=ImplicitFields.None)]
public readonly struct Amount
{
[ProtoIgnore]
public const decimal Scale = 100000m;
[ProtoIgnore]
public decimal Value { get; }
[ProtoMember(1)]
public long ScaledValue { get; }
public Amount(decimal value)
{
Value = value;
ScaledValue = checked((long)(value * Scale).Round(0));
}
public Amount(long scaledValue)
{
Value = scaledValue / Scale;
ScaledValue = scaledValue;
}
public static Amount CreateFrom(long scaledValue) => new Amount(scaledValue);
}
Проблема, с которой я столкнулся, заключается в том, что ctor не вызывается во время десериализации, несмотря на то, что SkipConstructor = false в ProtoContract, что приводит к правильной инициализации только свойства ScaledValue.
Я не могу использовать метод ProtoAfterDeserialization для установки свойства Value, поскольку структура доступна только для чтения.
Я попытался настроить собственный метод фабрики для protobuf-net, который будет использоваться при создании объекта, выполнив следующее:
var createFrom = typeof(Amount).GetMethod("CreateFrom", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(long) }, null);
RuntimeTypeModel.Default[typeof(Amount)].SetFactory(createFrom);
Но это неизменно приводит к « InvalidOperationException: операция недопустима из-за текущего состояния объекта. ». Я убедился, что метод CreateFrom найден (поэтому я передаю допустимый объект MethodInfo).
Есть идеи, как заставить это работать?