Я думаю, что этот вопрос является частным случаем более общего вопроса о создании типобезопасность через C# приложение. Мой пример здесь состоит из двух типов данных: Цены и веса. У них разные единицы измерения, поэтому никогда не следует пытаться назначить цену весу или наоборот. Оба под крышками - это действительно десятичные значения. (Я игнорирую тот факт, что могут быть конверсии, например, килограммы и т. Д.). Эта же идея может быть применена к строкам с определенными типами, такими как EmailAddress и UserLastName.
С некоторым кодом котельной плиты можно сделать либо явное преобразование, либо неявное преобразование между конкретными типами: цена и вес, а также базовый тип Десятичный.
public class Weight
{
private readonly Decimal _value;
public Weight(Decimal value)
{
_value = value;
}
public static explicit operator Weight(Decimal value)
{
return new Weight(value);
}
public static explicit operator Decimal(Weight value)
{
return value._value;
}
};
public class Price {
private readonly Decimal _value;
public Price(Decimal value) {
_value = value;
}
public static explicit operator Price(Decimal value) {
return new Price(value);
}
public static explicit operator Decimal(Price value)
{
return value._value;
}
};
С переопределением оператора «явный» можно получить более ограничительный набор вещей, который можно сделать с этими классами. Каждый раз, когда вы переходите от одного типа к другому, вы должны быть вручную. Например:
public void NeedsPrice(Price aPrice)
{
}
public void NeedsWeight(Weight aWeight)
{
}
public void NeedsDecimal(Decimal aDecimal)
{
}
public void ExplicitTest()
{
Price aPrice = (Price)1.23m;
Decimal aDecimal = 3.4m;
Weight aWeight = (Weight)132.0m;
// ok
aPrice = (Price)aDecimal;
aDecimal = (Decimal)aPrice;
// Errors need explicit case
aPrice = aDecimal;
aDecimal = aPrice;
//ok
aWeight = (Weight)aDecimal;
aDecimal = (Decimal) aWeight;
// Errors need explicit cast
aWeight = aDecimal;
aDecimal = aWeight;
// Errors (no such conversion exists)
aPrice = (Price)aWeight;
aWeight = (Weight)aPrice;
// Ok, but why would you ever do this.
aPrice = (Price)(Decimal)aWeight;
aWeight = (Weight)(Decimal)aPrice;
NeedsPrice(aPrice); //ok
NeedsDecimal(aPrice); //error
NeedsWeight(aPrice); //error
NeedsPrice(aDecimal); //error
NeedsDecimal(aDecimal); //ok
NeedsWeight(aDecimal); //error
NeedsPrice(aWeight); //error
NeedsDecimal(aWeight); //error
NeedsWeight(aWeight); //ok
}
Просто изменение «явные» операторы «неявные» операторы, заменив слова «явно» с «неявным» в коде, можно преобразовать назад и вперед к десятичному классу без какого-либо Дополнительная работа. Это приводит к тому, что Price и Weight ведут себя как Decimal, но вы по-прежнему не можете изменить цену на вес. Обычно это уровень безопасности типов, который я ищу.
public void ImplicitTest()
{
Price aPrice = 1.23m;
Decimal aDecimal = 3.4m;
Weight aWeight = 132.0m;
// ok implicit cast
aPrice = aDecimal;
aDecimal = aPrice;
// ok implicit cast
aWeight = aDecimal;
aDecimal = aWeight;
// Errors
aPrice = aWeight;
aWeight = aPrice;
NeedsPrice(aPrice); //ok
NeedsDecimal(aPrice); //ok
NeedsWeight(aPrice); //error
NeedsPrice(aDecimal); //ok
NeedsDecimal(aDecimal); //ok
NeedsWeight(aDecimal); //ok
NeedsPrice(aWeight); //error
NeedsDecimal(aWeight); //ok
NeedsWeight(aWeight); //ok
}
При выполнении этого для строки вместо десятичного. Мне нравится идея ответа Торарина о проверке null и передаче нулевого значения в преобразовании. например
public static implicit operator EMailAddress(string address)
{
// Make
// EmailAddress myvar=null
// and
// string aNullString = null;
// EmailAddress myvar = aNullString;
// give the same result.
if (address == null)
return null;
return new EMailAddress(address);
}
Чтобы получить эти классы работают как ключи словаря коллекций, вы также должны реализовать Equals, GetHashCode, оператор ==, а оператор! =
Чтобы сделать все это проще, я сделал класс ValueType, который я могу расширить, класс ValueType вызывает базовый тип для всех, кроме операторов преобразования.
Если это похоже на строку - это должна быть строка. Я не уверен, что это возможно и даже хорошая идея. – zerkms
Является ли класс строки дефектным? –
Никто не ожидал увидеть подобное. Просто создайте свой собственный класс. –