Adding and updating old propertyhelper code for dictionaries
This commit is contained in:
parent
ec4b3a29c0
commit
df16982697
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
internal class HtmlAttributePropertyHelper : PropertyHelper
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, PropertyHelper[]> ReflectionCache =
|
||||
new ConcurrentDictionary<Type, PropertyHelper[]>();
|
||||
|
||||
public static new PropertyHelper[] GetProperties(object instance)
|
||||
{
|
||||
return GetProperties(instance, CreateInstance, ReflectionCache);
|
||||
}
|
||||
|
||||
private static PropertyHelper CreateInstance(PropertyInfo property)
|
||||
{
|
||||
return new HtmlAttributePropertyHelper(property);
|
||||
}
|
||||
|
||||
public HtmlAttributePropertyHelper(PropertyInfo property)
|
||||
: base(property)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Name;
|
||||
}
|
||||
|
||||
protected set
|
||||
{
|
||||
base.Name = value == null ? null : value.Replace('_', '-');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
|
|
@ -33,3 +34,5 @@ using System.Runtime.InteropServices;
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Rendering.Test")]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
internal class PropertyHelper
|
||||
{
|
||||
// Delegate type for a by-ref property getter
|
||||
private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);
|
||||
|
||||
private static readonly MethodInfo CallPropertyGetterOpenGenericMethod =
|
||||
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertyGetter");
|
||||
|
||||
private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod =
|
||||
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertyGetterByReference");
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, PropertyHelper[]> ReflectionCache =
|
||||
new ConcurrentDictionary<Type, PropertyHelper[]>();
|
||||
|
||||
private readonly Func<object, object> _valueGetter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a fast property helper.
|
||||
///
|
||||
/// This constructor does not cache the helper. For caching, use GetProperties.
|
||||
/// </summary>
|
||||
public PropertyHelper(PropertyInfo property)
|
||||
{
|
||||
Contract.Assert(property != null);
|
||||
|
||||
Name = property.Name;
|
||||
_valueGetter = MakeFastPropertyGetter(property);
|
||||
}
|
||||
|
||||
public virtual string Name { get; protected set; }
|
||||
|
||||
public object GetValue(object instance)
|
||||
{
|
||||
return _valueGetter(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and caches fast property helpers that expose getters for every public get property on the
|
||||
/// underlying type.
|
||||
/// </summary>
|
||||
/// <param name="instance">the instance to extract property accessors for.</param>
|
||||
/// <returns>a cached array of all public property getters from the underlying type of target instance.</returns>
|
||||
public static PropertyHelper[] GetProperties(object instance)
|
||||
{
|
||||
return GetProperties(instance, CreateInstance, ReflectionCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a single fast property getter. The result is not cached.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
|
||||
/// <returns>a fast getter.</returns>
|
||||
/// <remarks>
|
||||
/// This method is more memory efficient than a dynamically compiled lambda, and about the
|
||||
/// same speed.
|
||||
/// </remarks>
|
||||
public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
|
||||
{
|
||||
Contract.Assert(propertyInfo != null);
|
||||
|
||||
var getMethod = propertyInfo.GetMethod;
|
||||
Contract.Assert(getMethod != null);
|
||||
Contract.Assert(!getMethod.IsStatic);
|
||||
Contract.Assert(getMethod.GetParameters().Length == 0);
|
||||
|
||||
// Instance methods in the CLR can be turned into static methods where the first parameter
|
||||
// is open over "target". This parameter is always passed by reference, so we have a code
|
||||
// path for value types and a code path for reference types.
|
||||
var typeInput = getMethod.DeclaringType;
|
||||
var typeOutput = getMethod.ReturnType;
|
||||
|
||||
Delegate callPropertyGetterDelegate;
|
||||
if (typeInput.IsValueType())
|
||||
{
|
||||
// Create a delegate (ref TDeclaringType) -> TValue
|
||||
var delegateType = typeof(ByRefFunc<,>).MakeGenericType(typeInput, typeOutput);
|
||||
var propertyGetterAsFunc = getMethod.CreateDelegate(delegateType);
|
||||
var callPropertyGetterClosedGenericMethod =
|
||||
CallPropertyGetterByReferenceOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
|
||||
callPropertyGetterDelegate =
|
||||
callPropertyGetterClosedGenericMethod.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a delegate TDeclaringType -> TValue
|
||||
var propertyGetterAsFunc = getMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(typeInput, typeOutput));
|
||||
var callPropertyGetterClosedGenericMethod =
|
||||
CallPropertyGetterOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
|
||||
callPropertyGetterDelegate =
|
||||
callPropertyGetterClosedGenericMethod.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc);
|
||||
}
|
||||
|
||||
return (Func<object, object>)callPropertyGetterDelegate;
|
||||
}
|
||||
|
||||
private static PropertyHelper CreateInstance(PropertyInfo property)
|
||||
{
|
||||
return new PropertyHelper(property);
|
||||
}
|
||||
|
||||
// Called via reflection
|
||||
private static object CallPropertyGetter<TDeclaringType, TValue>(Func<TDeclaringType, TValue> getter, object target)
|
||||
{
|
||||
return getter((TDeclaringType)target);
|
||||
}
|
||||
|
||||
// Called via reflection
|
||||
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(
|
||||
ByRefFunc<TDeclaringType, TValue> getter,
|
||||
object target)
|
||||
{
|
||||
var unboxed = (TDeclaringType)target;
|
||||
return getter(ref unboxed);
|
||||
}
|
||||
|
||||
protected static PropertyHelper[] GetProperties(
|
||||
object instance,
|
||||
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
|
||||
ConcurrentDictionary<Type, PropertyHelper[]> cache)
|
||||
{
|
||||
// Using an array rather than IEnumerable, as target will be called on the hot path numerous times.
|
||||
PropertyHelper[] helpers;
|
||||
|
||||
var type = instance.GetType();
|
||||
|
||||
if (!cache.TryGetValue(type, out helpers))
|
||||
{
|
||||
// We avoid loading indexed properties using the where statement.
|
||||
// Indexed properties are not useful (or valid) for grabbing properties off an anonymous object.
|
||||
var properties = type.GetRuntimeProperties().Where(
|
||||
prop => prop.GetIndexParameters().Length == 0 &&
|
||||
prop.GetMethod != null &&
|
||||
prop.GetMethod.IsPublic &&
|
||||
!prop.GetMethod.IsStatic);
|
||||
|
||||
helpers = properties.Select(p => createPropertyHelper(p)).ToArray();
|
||||
cache.TryAdd(type, helpers);
|
||||
}
|
||||
|
||||
return helpers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
internal static class TypeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Given an object, adds each instance property with a public get method as a key and its
|
||||
/// associated value to a dictionary.
|
||||
/// </summary>
|
||||
//
|
||||
// The implementation of PropertyHelper will cache the property accessors per-type. This is
|
||||
// faster when the the same type is used multiple times with ObjectToDictionary.
|
||||
public static IDictionary<string, object> ObjectToDictionary(object value)
|
||||
{
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
foreach (var helper in PropertyHelper.GetProperties(value))
|
||||
{
|
||||
dictionary.Add(helper.Name, helper.GetValue(value));
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class HtmlAttributePropertyHelperTest
|
||||
{
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_RenamesPropertyNames()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { bar_baz = "foo" };
|
||||
var property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
var helper = new HtmlAttributePropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar_baz", property.Name);
|
||||
Assert.Equal("bar-baz", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_ReturnsNameCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = "bar" };
|
||||
var property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
var helper = new HtmlAttributePropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", property.Name);
|
||||
Assert.Equal("foo", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_ReturnsValueCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { bar = "baz" };
|
||||
var property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
var helper = new HtmlAttributePropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar", helper.Name);
|
||||
Assert.Equal("baz", helper.GetValue(anonymous));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_ReturnsValueCorrectly_ForValueTypes()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = 32 };
|
||||
var property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
var helper = new HtmlAttributePropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", helper.Name);
|
||||
Assert.Equal(32, helper.GetValue(anonymous));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_ReturnsCachedPropertyHelper()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = "bar" };
|
||||
|
||||
// Act
|
||||
var helpers1 = HtmlAttributePropertyHelper.GetProperties(anonymous);
|
||||
var helpers2 = HtmlAttributePropertyHelper.GetProperties(anonymous);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, helpers1.Length);
|
||||
Assert.Same(helpers1, helpers2);
|
||||
Assert.Same(helpers1[0], helpers2[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HtmlAttributePropertyHelper_DoesNotShareCacheWithPropertyHelper()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { bar_baz1 = "foo" };
|
||||
|
||||
// Act
|
||||
var helpers1 = HtmlAttributePropertyHelper.GetProperties(anonymous);
|
||||
var helpers2 = PropertyHelper.GetProperties(anonymous);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, helpers1.Length);
|
||||
Assert.Equal(1, helpers2.Length);
|
||||
|
||||
Assert.NotEqual<PropertyHelper[]>(helpers1, helpers2);
|
||||
Assert.NotEqual<PropertyHelper>(helpers1[0], helpers2[0]);
|
||||
|
||||
Assert.IsType<HtmlAttributePropertyHelper>(helpers1[0]);
|
||||
Assert.IsNotType<HtmlAttributePropertyHelper>(helpers2[0]);
|
||||
|
||||
Assert.Equal("bar-baz1", helpers1[0].Name);
|
||||
Assert.Equal("bar_baz1", helpers2[0].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class PropertyHelperTest
|
||||
{
|
||||
[Fact]
|
||||
public void PropertyHelper_ReturnsNameCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = "bar" };
|
||||
PropertyInfo property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
PropertyHelper helper = new PropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", property.Name);
|
||||
Assert.Equal("foo", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ReturnsValueCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { bar = "baz" };
|
||||
PropertyInfo property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
PropertyHelper helper = new PropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar", helper.Name);
|
||||
Assert.Equal("baz", helper.GetValue(anonymous));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ReturnsValueCorrectly_ForValueTypes()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = 32 };
|
||||
var property = anonymous.GetType().GetProperties().First();
|
||||
|
||||
// Act
|
||||
var helper = new PropertyHelper(property);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", helper.Name);
|
||||
Assert.Equal(32, helper.GetValue(anonymous));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ReturnsCachedPropertyHelper()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { foo = "bar" };
|
||||
|
||||
// Act
|
||||
var helpers1 = PropertyHelper.GetProperties(anonymous);
|
||||
var helpers2 = PropertyHelper.GetProperties(anonymous);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, helpers1.Length);
|
||||
Assert.Same(helpers1, helpers2);
|
||||
Assert.Same(helpers1[0], helpers2[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_DoesNotChangeUnderscores()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new { bar_baz2 = "foo" };
|
||||
|
||||
// Act + Assert
|
||||
var helper = Assert.Single(PropertyHelper.GetProperties(anonymous));
|
||||
Assert.Equal("bar_baz2", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_DoesNotFindPrivateProperties()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new PrivateProperties();
|
||||
|
||||
// Act + Assert
|
||||
var helper = Assert.Single(PropertyHelper.GetProperties(anonymous));
|
||||
Assert.Equal("Prop1", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_DoesNotFindStaticProperties()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new Static();
|
||||
|
||||
// Act + Assert
|
||||
var helper = Assert.Single(PropertyHelper.GetProperties(anonymous));
|
||||
Assert.Equal("Prop5", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_DoesNotFindSetOnlyProperties()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new SetOnly();
|
||||
|
||||
// Act + Assert
|
||||
var helper = Assert.Single(PropertyHelper.GetProperties(anonymous));
|
||||
Assert.Equal("Prop6", helper.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_WorksForStruct()
|
||||
{
|
||||
// Arrange
|
||||
var anonymous = new MyProperties();
|
||||
|
||||
anonymous.IntProp = 3;
|
||||
anonymous.StringProp = "Five";
|
||||
|
||||
// Act + Assert
|
||||
var helper1 = Assert.Single(PropertyHelper.GetProperties(anonymous).Where(prop => prop.Name == "IntProp"));
|
||||
var helper2 = Assert.Single(PropertyHelper.GetProperties(anonymous).Where(prop => prop.Name == "StringProp"));
|
||||
Assert.Equal(3, helper1.GetValue(anonymous));
|
||||
Assert.Equal("Five", helper2.GetValue(anonymous));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ForDerivedClass()
|
||||
{
|
||||
// Arrange
|
||||
var derived = new DerivedClass { PropA = "propAValue", PropB = "propBValue" };
|
||||
|
||||
// Act
|
||||
var helpers = PropertyHelper.GetProperties(derived).ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(helpers);
|
||||
Assert.Equal(2, helpers.Length);
|
||||
|
||||
var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA"));
|
||||
var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB"));
|
||||
|
||||
Assert.Equal("propAValue", propAHelper.GetValue(derived));
|
||||
Assert.Equal("propBValue", propBHelper.GetValue(derived));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ForDerivedClass_WithNew()
|
||||
{
|
||||
// Arrange
|
||||
var derived = new DerivedClassWithNew { PropA = "propAValue" };
|
||||
|
||||
// Act
|
||||
var helpers = PropertyHelper.GetProperties(derived).ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(helpers);
|
||||
Assert.Equal(2, helpers.Length);
|
||||
|
||||
var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA"));
|
||||
var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB"));
|
||||
|
||||
Assert.Equal("propAValue", propAHelper.GetValue(derived));
|
||||
Assert.Equal("Newed", propBHelper.GetValue(derived));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertyHelper_ForDerived_WithVirtual()
|
||||
{
|
||||
// Arrange
|
||||
var derived = new DerivedClassWithOverride { PropA = "propAValue", PropB = "propBValue" };
|
||||
|
||||
// Act
|
||||
var helpers = PropertyHelper.GetProperties(derived).ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(helpers);
|
||||
Assert.Equal(2, helpers.Length);
|
||||
|
||||
var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA"));
|
||||
var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB"));
|
||||
|
||||
Assert.Equal("Overriden", propAHelper.GetValue(derived));
|
||||
Assert.Equal("propBValue", propBHelper.GetValue(derived));
|
||||
}
|
||||
|
||||
private class Static
|
||||
{
|
||||
public static int Prop2 { get; set; }
|
||||
public int Prop5 { get; set; }
|
||||
}
|
||||
|
||||
private struct MyProperties
|
||||
{
|
||||
public int IntProp { get; set; }
|
||||
public string StringProp { get; set; }
|
||||
}
|
||||
|
||||
private class SetOnly
|
||||
{
|
||||
public int Prop2 { set { } }
|
||||
public int Prop6 { get; set; }
|
||||
}
|
||||
|
||||
private class PrivateProperties
|
||||
{
|
||||
public int Prop1 { get; set; }
|
||||
protected int Prop2 { get; set; }
|
||||
private int Prop3 { get; set; }
|
||||
}
|
||||
|
||||
public class BaseClass
|
||||
{
|
||||
public string PropA { get; set; }
|
||||
|
||||
protected string PropProtected { get; set; }
|
||||
}
|
||||
|
||||
public class DerivedClass : BaseClass
|
||||
{
|
||||
public string PropB { get; set; }
|
||||
}
|
||||
|
||||
public class BaseClassWithVirtual
|
||||
{
|
||||
public virtual string PropA { get; set; }
|
||||
public string PropB { get; set; }
|
||||
}
|
||||
|
||||
public class DerivedClassWithNew : BaseClassWithVirtual
|
||||
{
|
||||
public new string PropB { get { return "Newed"; } }
|
||||
}
|
||||
|
||||
public class DerivedClassWithOverride : BaseClassWithVirtual
|
||||
{
|
||||
public override string PropA { get { return "Overriden"; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class TypeHelperTest
|
||||
{
|
||||
[Fact]
|
||||
public void ObjectToDictionary_WithNullObject_ReturnsEmptyDictionary()
|
||||
{
|
||||
// Arrange
|
||||
object value = null;
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(0, dictValues.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectToDictionary_WithPlainObjectType_ReturnsEmptyDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var value = new object();
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(0, dictValues.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectToDictionary_WithPrimitiveType_LooksUpPublicProperties()
|
||||
{
|
||||
// Arrange
|
||||
var value = "test";
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(1, dictValues.Count);
|
||||
Assert.Equal(4, dictValues["Length"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectToDictionary_WithAnonymousType_LooksUpProperties()
|
||||
{
|
||||
// Arrange
|
||||
var value = new { test = "value", other = 1 };
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(2, dictValues.Count);
|
||||
Assert.Equal("value", dictValues["test"]);
|
||||
Assert.Equal(1, dictValues["other"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectToDictionary_ReturnsCaseInsensitiveDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var value = new { TEST = "value", oThEr = 1 };
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(2, dictValues.Count);
|
||||
Assert.Equal("value", dictValues["test"]);
|
||||
Assert.Equal(1, dictValues["other"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectToDictionary_ReturnsInheritedProperties()
|
||||
{
|
||||
// Arrange
|
||||
var value = new ThreeDPoint() {X = 5, Y = 10, Z = 17};
|
||||
|
||||
// Act
|
||||
var dictValues = TypeHelper.ObjectToDictionary(value);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dictValues);
|
||||
Assert.Equal(3, dictValues.Count);
|
||||
Assert.Equal(5, dictValues["X"]);
|
||||
Assert.Equal(10, dictValues["Y"]);
|
||||
Assert.Equal(17, dictValues["Z"]);
|
||||
}
|
||||
|
||||
private class Point
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
}
|
||||
|
||||
private class ThreeDPoint : Point
|
||||
{
|
||||
public int Z { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue