Cleans up IPropertyType since we don't need the method ConvertAssignedValue as an abstraction

This commit is contained in:
Shannon
2019-11-19 15:52:56 +11:00
parent e537a55181
commit e366f99105
3 changed files with 125 additions and 134 deletions

View File

@@ -295,7 +295,7 @@ namespace Umbraco.Core.Models
if (!PropertyType.SupportsPublishing)
throw new NotSupportedException("Property type does not support publishing.");
var origValue = pvalue.PublishedValue;
pvalue.PublishedValue = PropertyType.ConvertAssignedValue(pvalue.EditedValue);
pvalue.PublishedValue = ConvertAssignedValue(pvalue.EditedValue);
DetectChanges(pvalue.EditedValue, origValue, nameof(Values), PropertyValueComparer, false);
}
@@ -306,7 +306,7 @@ namespace Umbraco.Core.Models
if (!PropertyType.SupportsPublishing)
throw new NotSupportedException("Property type does not support publishing.");
var origValue = pvalue.PublishedValue;
pvalue.PublishedValue = PropertyType.ConvertAssignedValue(null);
pvalue.PublishedValue = ConvertAssignedValue(null);
DetectChanges(pvalue.EditedValue, origValue, nameof(Values), PropertyValueComparer, false);
}
@@ -324,7 +324,7 @@ namespace Umbraco.Core.Models
var (pvalue, change) = GetPValue(culture, segment, true);
var origValue = pvalue.EditedValue;
var setValue = PropertyType.ConvertAssignedValue(value);
var setValue = ConvertAssignedValue(value);
pvalue.EditedValue = setValue;
@@ -380,6 +380,128 @@ namespace Umbraco.Core.Models
return (pvalue, change);
}
/// <inheritdoc />
public object ConvertAssignedValue(object value) => TryConvertAssignedValue(value, true, out var converted) ? converted : null;
/// <summary>
/// Tries to convert a value assigned to a property.
/// </summary>
/// <remarks>
/// <para></para>
/// </remarks>
private bool TryConvertAssignedValue(object value, bool throwOnError, out object converted)
{
var isOfExpectedType = IsOfExpectedPropertyType(value);
if (isOfExpectedType)
{
converted = value;
return true;
}
// isOfExpectedType is true if value is null - so if false, value is *not* null
// "garbage-in", accept what we can & convert
// throw only if conversion is not possible
var s = value.ToString();
converted = null;
switch (ValueStorageType)
{
case ValueStorageType.Nvarchar:
case ValueStorageType.Ntext:
{
converted = s;
return true;
}
case ValueStorageType.Integer:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convInt = value.TryConvertTo<int>();
if (convInt)
{
converted = convInt.Result;
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(int), Alias);
return false;
case ValueStorageType.Decimal:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convDecimal = value.TryConvertTo<decimal>();
if (convDecimal)
{
// need to normalize the value (change the scaling factor and remove trailing zeros)
// because the underlying database is going to mess with the scaling factor anyways.
converted = convDecimal.Result.Normalize();
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(decimal), Alias);
return false;
case ValueStorageType.Date:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convDateTime = value.TryConvertTo<DateTime>();
if (convDateTime)
{
converted = convDateTime.Result;
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(DateTime), Alias);
return false;
default:
throw new NotSupportedException($"Not supported storage type \"{ValueStorageType}\".");
}
}
private static void ThrowTypeException(object value, Type expected, string alias)
{
throw new InvalidOperationException($"Cannot assign value \"{value}\" of type \"{value.GetType()}\" to property \"{alias}\" expecting type \"{expected}\".");
}
/// <summary>
/// Determines whether a value is of the expected type for this property type.
/// </summary>
/// <remarks>
/// <para>If the value is of the expected type, it can be directly assigned to the property.
/// Otherwise, some conversion is required.</para>
/// </remarks>
private bool IsOfExpectedPropertyType(object value)
{
// null values are assumed to be ok
if (value == null)
return true;
// check if the type of the value matches the type from the DataType/PropertyEditor
// then it can be directly assigned, anything else requires conversion
var valueType = value.GetType();
switch (ValueStorageType)
{
case ValueStorageType.Integer:
return valueType == typeof(int);
case ValueStorageType.Decimal:
return valueType == typeof(decimal);
case ValueStorageType.Date:
return valueType == typeof(DateTime);
case ValueStorageType.Nvarchar:
return valueType == typeof(string);
case ValueStorageType.Ntext:
return valueType == typeof(string);
default:
throw new NotSupportedException($"Not supported storage type \"{ValueStorageType}\".");
}
}
protected override void PerformDeepClone(object clone)
{
base.PerformDeepClone(clone);

View File

@@ -210,128 +210,6 @@ namespace Umbraco.Core.Models
return Variations.ValidateVariation(culture, segment, true, wildcards, false);
}
/// <summary>
/// Determines whether a value is of the expected type for this property type.
/// </summary>
/// <remarks>
/// <para>If the value is of the expected type, it can be directly assigned to the property.
/// Otherwise, some conversion is required.</para>
/// </remarks>
private bool IsOfExpectedPropertyType(object value)
{
// null values are assumed to be ok
if (value == null)
return true;
// check if the type of the value matches the type from the DataType/PropertyEditor
// then it can be directly assigned, anything else requires conversion
var valueType = value.GetType();
switch (ValueStorageType)
{
case ValueStorageType.Integer:
return valueType == typeof(int);
case ValueStorageType.Decimal:
return valueType == typeof(decimal);
case ValueStorageType.Date:
return valueType == typeof(DateTime);
case ValueStorageType.Nvarchar:
return valueType == typeof(string);
case ValueStorageType.Ntext:
return valueType == typeof(string);
default:
throw new NotSupportedException($"Not supported storage type \"{ValueStorageType}\".");
}
}
/// <inheritdoc />
public object ConvertAssignedValue(object value) => TryConvertAssignedValue(value, true, out var converted) ? converted : null;
/// <summary>
/// Tries to convert a value assigned to a property.
/// </summary>
/// <remarks>
/// <para></para>
/// </remarks>
private bool TryConvertAssignedValue(object value, bool throwOnError, out object converted)
{
var isOfExpectedType = IsOfExpectedPropertyType(value);
if (isOfExpectedType)
{
converted = value;
return true;
}
// isOfExpectedType is true if value is null - so if false, value is *not* null
// "garbage-in", accept what we can & convert
// throw only if conversion is not possible
var s = value.ToString();
converted = null;
switch (ValueStorageType)
{
case ValueStorageType.Nvarchar:
case ValueStorageType.Ntext:
{
converted = s;
return true;
}
case ValueStorageType.Integer:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convInt = value.TryConvertTo<int>();
if (convInt)
{
converted = convInt.Result;
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(int), Alias);
return false;
case ValueStorageType.Decimal:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convDecimal = value.TryConvertTo<decimal>();
if (convDecimal)
{
// need to normalize the value (change the scaling factor and remove trailing zeros)
// because the underlying database is going to mess with the scaling factor anyways.
converted = convDecimal.Result.Normalize();
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(decimal), Alias);
return false;
case ValueStorageType.Date:
if (s.IsNullOrWhiteSpace())
return true; // assume empty means null
var convDateTime = value.TryConvertTo<DateTime>();
if (convDateTime)
{
converted = convDateTime.Result;
return true;
}
if (throwOnError)
ThrowTypeException(value, typeof(DateTime), Alias);
return false;
default:
throw new NotSupportedException($"Not supported storage type \"{ValueStorageType}\".");
}
}
private static void ThrowTypeException(object value, Type expected, string alias)
{
throw new InvalidOperationException($"Cannot assign value \"{value}\" of type \"{value.GetType()}\" to property \"{alias}\" expecting type \"{expected}\".");
}
/// <summary>
/// Sanitizes a property type alias.
/// </summary>