2015-10-13 67 views
0

我想写这个方法:访问属性通过传递拉姆达

public static T Nullify<T>(T item, params Func<T, object> [] properties) 
{ 
    // Sets any specified properties to null, returns the object. 
} 

我会这样称呼它:

var kitten = new Kitten() { Name = "Mr Fluffykins", FurColour = "Brown" }; 

var anonymousKitten = Nullify(kitten, c => c.Name); 

但是我不确定如何做到这一点。有任何想法吗?

+0

你想要一个新的实例,或者用空的属性一样吗?目前尚不清楚,因为你的方法返回'无效' – ken2k

+0

对不起,我复制代码时发生错字。同样的例子。 – NibblyPig

回答

5

一反璞归真的方法是做到这一点(它并不需要是扩展方法)

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; 
} 

使用

item.Nullify(i => i.PropertyName, i => i.PropertyName2) 
1

您需要在properties中传递“setter方法”而不是“reader method”。

static void Nullify<T, D>(T item, params Action<T, D>[] properties) 
    where D : class 
{ 
    foreach (var property in properties) 
    { 
     property(item, null); 
    } 
} 

用法:

Nullify<Kitten, string>(kitten, (c, d) => { c.Name = d; }); 

但是,这将只设置数据为您服务。如果你想要一个副本,然后应用性能,该项目很可能必须是可克隆(或者你也可以去,虽然有些地狱反射):

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 }; 
    } 
} 

使用

var anonymousKitten = Nullify(kitten, (c, d) => { c.Name = d; }); 
0

无需修改方法定义了:

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(); 
     } 
    } 
} 

看起来虽然有点哈克....