The goal: create an extension method that will make it easy to create FormCollection objects. The method is a helper for unit testing ASP.NET MVC code.
public static FormCollection ToFormCollection(this object data) { var namesAndValues = data.GetType() .GetProperties() .WhereValueIsNotDefaultValue(data) .ToNameValueCollection(data); return new FormCollection(namesAndValues); }
The extension method itself relies on a couple private extension methods:
static IEnumerable<PropertyInfo> WhereValueIsNotDefaultValue( this IEnumerable<PropertyInfo> properties, object source) { foreach(var p in properties) { var value = p.GetValue(source, null); if(value != (p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null)) { yield return p; } } } static NameValueCollection ToNameValueCollection( this IEnumerable<PropertyInfo> properties, object source) { return properties.Aggregate( new NameValueCollection(), (nvc,pi) => { var value = pi.GetValue(source, null); nvc.Add(pi.Name, value.ToString()); return nvc; }); }
The code mostly works. This test passes:
public void should_copy_property_values() { var expectedName = "Scott"; var expectedHireDate = new DateTime(2010, 1, 1); var data = new Employee { Name = expectedName, HireDate = expectedHireDate }.ToFormCollection(); Assert.IsTrue(data["Name"] == expectedName); Assert.IsTrue(data["HireDate"] == expectedHireDate.ToString()); }
However, the helper should not put entries in the FormCollection for properties holding a default value, and this test fails:
public void should_not_copy_default_values() { var data = new Employee { Name = "", HireDate = DateTime.Now }.ToFormCollection(); Assert.IsNull(data["Tags"]); Assert.IsNull(data["Id"]); }
Employee is defined as:
public class Employee { public int Id { get; set; } public string Name { get; set; } public DateTime HireDate { get; set; } public string Tags { get; set; } }
Hint: the first assert passes – it’s the assert on data[“Id”] that fails.
Comments
It might be easier to read if implicit typing was not used for method calls. I've tried to only use var for object construction and where unavoidable for anonymous types.
That should compare value.
Thanks,
Amir