2015-10-13 66 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(); 
     } 
    } 
} 

看起來雖然有點哈克....