Reputation: 52932
I am trying to write this method:
public static T Nullify<T>(T item, params Func<T, object> [] properties)
{
// Sets any specified properties to null, returns the object.
}
I will call it like this:
var kitten = new Kitten() { Name = "Mr Fluffykins", FurColour = "Brown" };
var anonymousKitten = Nullify(kitten, c => c.Name);
However I am unsure of how to do this. Any ideas?
Upvotes: 0
Views: 1370
Reputation: 8256
Another approach is to do this (it doesn't need to be an extension method)
public static T Nullify<T>(this T item, params Expression<Func<T, object>> [] properties)
{
foreach(var property in properties)
{
var memberSelectorExpression = property.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var propertyInfo = memberSelectorExpression.Member as PropertyInfo;
if (propertyInfo != null)
{
propertyInfo.SetValue(item, null, null);
}
}
}
return item;
}
Usage
item.Nullify(i => i.PropertyName, i => i.PropertyName2)
Upvotes: 5
Reputation: 48975
Without modifying your method definition much:
namespace ConsoleApplication
{
public class Kitten : ISimpleClone<Kitten>
{
public string Name { get; set; }
public string FurColour { get; set; }
public int? Number { get; set; }
public Kitten SimpleClone()
{
return new Kitten { Name = this.Name, FurColour = this.FurColour, Number = this.Number };
}
}
public interface ISimpleClone<T>
{
T SimpleClone();
}
public class Program
{
public static PropertyInfo GetProperty<TObject, TProperty>(Expression<Func<TObject, TProperty>> propertyExpression)
{
MemberExpression body = propertyExpression.Body as MemberExpression;
if (body == null)
{
var unaryExp = propertyExpression.Body as UnaryExpression;
if (unaryExp != null)
{
body = ((UnaryExpression)unaryExp).Operand as MemberExpression;
}
}
return body.Member as PropertyInfo;
}
public static T Nullify<T>(T item, params Expression<Func<T, object>>[] properties)
where T : ISimpleClone<T>
{
// Creates a new instance
var newInstance = item.SimpleClone();
// Gets the properties that will be null
var propToNull = properties.Select(z => GetProperty<T, object>(z));
var filteredProp = propToNull
.Where(z => !z.PropertyType.IsValueType || Nullable.GetUnderlyingType(z.PropertyType) != null) // Can be null
.Where(z => z.GetSetMethod(false) != null && z.CanWrite); // Can be set
foreach (var prop in filteredProp)
{
prop.SetValue(newInstance, null);
}
return newInstance;
}
public static void Main(string[] args)
{
var kitten = new Kitten() { Name = "Mr Fluffykins", FurColour = "Brown", Number = 12 };
var anonymousKitten = Nullify(kitten, c => c.Name, c => c.Number);
Console.Read();
}
}
}
Looks a bit hacky though....
Upvotes: 0
Reputation: 1172
You'd need to pass a "setter method" not a "reader method" in properties
.
static void Nullify<T, D>(T item, params Action<T, D>[] properties)
where D : class
{
foreach (var property in properties)
{
property(item, null);
}
}
usage:
Nullify<Kitten, string>(kitten, (c, d) => { c.Name = d; });
But this will just set the data for you. If you want a copy and then apply the properties, the items would probably have to be clonable (alternatively you can go though some hell with reflection):
static T Nullify<T, D>(T item, params Action<T, D>[] properties)
where D : class
where T : ICloneable
{
T copy = (T)item.Clone();
foreach (var property in properties)
{
property(copy, null);
}
return copy;
}
class Kitten : ICloneable
{
public string Name { get; set; }
public string FurColour { get; set; }
public object Clone()
{
return new Kitten() { Name = this.Name, FurColour = this.FurColour };
}
}
usage
var anonymousKitten = Nullify(kitten, (c, d) => { c.Name = d; });
Upvotes: 2