2014-01-06 87 views
0

我有下面的類專營:C#:獲取屬性的名稱,並檢查它的價值

public class Franchise 
     { 
      public string FolderName { get; set; } 
      public string InstallerExeName { get; set; } 
     } 

我有檢查在數據庫中的所有特權中uniqness特定的屬性值的方法。

public bool ValidateFolderName(string folderName) 
     { 
      var allFranchises = _franchiseService.GetAll(); 
      var result = allFranchises.Any(f => f.FolderName == folderName); 
      return result; 
     } 

的問題是我要檢查他人財產爲uniqness:

public bool ValidateInstallerExeName(string installerExeName) 
     { 
      var allFranchises = _franchiseService.GetAll(); 
      var result = allFranchises.Any(f => f.InstallerExeName == installerExeName); 
      return result; 
     } 

我想通過一個通用的方法,以避免重複代碼。喜歡的東西:

public bool ValidateProperty(string propertyName) 
     { 
      var allFranchises = _franchiseService.GetAll(); 
      // Not sure how to write this line 
      var result = allFranchises.Any(f => f.[propertyName] == propertyName); 
      return result; 
     } 

的問題是我不知道如何重新寫這行代碼,以便它可以獲取屬性名稱和所提供的參數檢查其值:

var result = allFranchises.Any(f => f.[propertyName] == propertyName); 

我知道我可以做這樣的事情與反思:

franchise.GetType().GetProperty(propertyName).GetValue(franchise, null);

,但我不知道我怎樣才能使這個適合我的情況。任何工作示例的幫助將不勝感激。謝謝!

回答

1

下面是使用反射一個完整的工作示例:

class Program 
{ 
    private static List<Franchise> allFranchises; 

    static void Main(string[] args) 
    { 
     allFranchises = new List<Franchise> 
     { 
      new Franchise() { [email protected]"c:\1", InstallerExeName="1.exe" }, 
      new Franchise() { [email protected]"c:\2", InstallerExeName="2.exe" }, 
      new Franchise() { [email protected]"c:\3", InstallerExeName="3.exe" }, 
      new Franchise() { [email protected]"c:\4", InstallerExeName="4.exe" }, 
      new Franchise() { [email protected]"c:\5", InstallerExeName="5.exe" }, 
     }; 

     Console.WriteLine(ValidateProperty("FolderName", @"c:\2", allFranchises)); 
     Console.WriteLine(ValidateProperty("InstallerExeName", "5.exe", allFranchises)); 
     Console.WriteLine(ValidateProperty("FolderName", @"c:\7", allFranchises)); 
     Console.WriteLine(ValidateProperty("InstallerExeName", "12.exe", allFranchises)); 
    } 

    public static bool ValidateProperty(string propertyName, object propertyValue, IEnumerable<Franchise> validateAgainst) 
    { 
     PropertyInfo propertyInfo = typeof(Franchise).GetProperty(propertyName); 
     return validateAgainst.Any(f => propertyInfo.GetValue(f, null) == propertyValue); 
    } 
} 

public class Franchise 
{ 
    public string FolderName { get; set; } 
    public string InstallerExeName { get; set; } 
} 

它會打印出:

True 
True 
False 
False 

預期。

+0

謝謝你的回答!我試過你的例子,但它只能在.net 4.5版本的框架中使用。看來'propertyInfo.GetValue(f)'在4.0(我正在使用)中沒有采用相同的參數。 – Mdb

+0

@Mdb是的,似乎4.0缺少這個單參數過載。我修改了這個例子,現在可以和4.0一起使用。 – mrzli

+0

是的,我查看了文檔並修復了這個問題。再次感謝你! – Mdb

0

你可以使用擴展方法:

public static bool ValidateProperty(
    this IEnumerable<Franchise> franchises, 
    string property, 
    object value) 
{ 
    var prop = typeof(Franchise).GetProperty(property); 
    if (prop == null) 
     throw new ArgumentException("Property does not exist"); 
    return franchises.Any(f => 
     prop.GetValue(f) == value); 
} 

使用方法如下:

var r = _franchiseService.GetAll().ValidateProperty("FolderName", "myfolder1"); 
1
public bool ValidateProperty<TType, TPropertyType>(Func<TType, TPropertyType> propertySelector, TPropertyType propertyValue) 
{ 
    return _franchiseService.GetAll().Any(f => propertySelector(f) == propertyValue); 
} 

你可以這樣調用:

if(ValidateProperty(x => x.FirstName, "Joe")) 

這不使用反射,你有智能感知你的財產名稱也是如此。

+0

它還有一個額外的好處,就是可以在服務器上執行O/RM來執行,而不是下載整個表格並在客戶端執行檢查(假設您實際上是從某個數據庫中讀取數據)。例如,您只需使用Expression >,它可以在'IQueryable.Any'中使用。當然,它也幾乎沒用,因爲你不是消除重複,而是添加它。你真的覺得'ValidateProperty(x => x.PropertyName,val);'比'service.Any(x => x.PropertyName == val)更簡單;''? – Luaan

0

您可以生成你想要使用System.Linq.Expressions

public class Franchise 
{ 
    public string FolderName { get; set; } 
    public string InstallerExeName { get; set; } 

    bool ValidateProperty(string propertyName) { 
    var allFranchises = new List<Franchise>(); 
    var parameter = Expression.Parameter(typeof(Franchise)); 
    var property = Expression.Property(parameter, propertyName); 
    var thisExpression = Expression.Constant(this, typeof(Franchise)); 
    var value = Expression.Property(thisExpression, propertyName); 
    var notThis = Expression.ReferenceNotEqual(thisExpression, property); 
    var equal = Expression.Equal(value, property); 
    var lambda = Expression.Lambda<Func<Franchise, bool>>(Expression.And(notThis, equal)); 


    // lamda is now the equivalent of: 
    // x => !object.ReferenceEquals(this, x) && object.Equals(x.Property, this.Property)  
    return allFranchises.Any(lambda.Compile()); 
    } 
} 

功能如果allFranchises的類型爲IQueryable的使用allFranchises.Any(lambda)

你也可以緩存,如果你擔心性能,供以後使用的表達。 }