2013-10-24 20 views
1

這是我的方法。請注意,我對泛型參數R返回相當於可空類型:我可以創建一個採用值類型或引用類型的泛型方法,但始終返回可爲空的類型

public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression) 
     where T : Attribute 
     where R : struct 
    { 
     if (a == null) 
      return null; 

     PropertyInfo p = GetProperty(expression); 
     if (p == null) 
      return null; 

     return (R)p.GetValue(a, null); 
    } 

我可以用它在呼叫得到一個屬性的這樣的值:

//I don't throw exceptions for invalid or missing calls 
//because I want to chain the calls together: 
int maximumLength4 = instance.GetProperty(x => x.ToString()) 
          .GetAttribute<StringLengthAttribute>() 
          .GetValue(x => x.MaximumLength) 
          .GetValueOrDefault(50); 

我想使用相同的通用方法處理字符串:

//I'd like to use the GetValue generic method with strings as well as integers 
string erroMessage = instance.GetProperty(x => x.ToString()) 
          .GetAttribute<StringLengthAttribute>() 
          .GetValue(x => x.ErrorMessage); 

,但它不會編譯:

類型「R」必須是一個非空值類型,以便在通用類型或方法「System.Nullable」

無法隱式轉換類型用它作爲 參數「T」'字符串?以「字符串」

有什麼訣竅,我可以使用這裏得到相同的方法簽名,但得到的仿製藥來推斷返回類型爲一體,可以爲空?

這是一些測試代碼,以表明它適用於整數值:

//[StringLength(256)] 
//public string Name { get; set; } 
PropertyInfo info = ReflectionAPI.GetProperty<Organisation, String>(x => x.Name);//not null 
StringLengthAttribute attr = info.GetAttribute<StringLengthAttribute>();//not null 
int? maximumLength = attr.GetValue(x => x.MaximumLength);//256 
int? minimumLength = attr.GetValue(x => x.MinimumLength);//0 

PropertyInfo info2 = ReflectionAPI.GetProperty<Organisation, int>(x => x.ID);//not null 
StringLengthAttribute attr2 = info2.GetAttribute<StringLengthAttribute>();//null because ID doesn't have the attribute 
int? maximumLength2 = attr2.GetValue(x => x.MaximumLength);//null 
int? minimumLength2 = attr2.GetValue(x => x.MinimumLength);//null 

//I can use the GetProperty extension method on an instance 
Organisation instance = (Organisation)null; 
PropertyInfo info3 = instance.GetProperty(x => x.ToString());//null because its a method call not a property 
StringLengthAttribute attr3 = info3.GetAttribute<StringLengthAttribute>();//null 
int? maximumLength3 = attr3.GetValue(x => x.MaximumLength);//null 
int? minimumLength3 = attr3.GetValue(x => x.MinimumLength);//null 

這是我ReflectionAPI的休息:

public static class ReflectionAPI 
{ 

    public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression) 
     where T : Attribute 
    { 
     if (a == null) 
      return null; 

     PropertyInfo p = GetProperty(expression); 
     if (p == null) 
      return null; 

     return (R)p.GetValue(a, null); 
    } 

    public static T GetAttribute<T>(this PropertyInfo p) where T : Attribute 
    { 
     if (p == null) 
      return null; 

     return p.GetCustomAttributes(false).OfType<T>().LastOrDefault(); 
    } 

    public static PropertyInfo GetProperty<T, R>(Expression<Func<T, R>> expression) 
    { 
     if (expression == null) 
      return null; 

     MemberExpression memberExpression = expression.Body as MemberExpression; 
     if (memberExpression == null) 
      return null; 

     return memberExpression.Member as PropertyInfo; 
    } 
} 

回答

4

沒有,有沒有個人簽名,可以做到這 - 沒有辦法說「R的可空類型,R本身爲參考類型,或Nullable<R>爲非空值類型」。

您可以有不同的方法,每一個與R不同的約束條件 - 但你要麼必須提供不同的名稱,或使用horrible hacks有效超載類型參數約束。

爲了簡單起見,我懷疑你應該在這裏基本上有兩個不同的方法名稱。所以簽名:

public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression) 
    where T : Attribute 
    where R : struct 

public static R GetReference<T, R>(this T a, Expression<Func<T, R>> expression) 
    where T : Attribute 
    where R : class 

兩個旁白:

  • 傳統類型參數入手T,例如TInputTResult
  • 你爲什麼在GetValue上使用表達式樹?爲什麼不採取Func<T, R>並執行它?

由於第二個小點的例子:

public static Nullable<R> GetValue<T, R>(this T a, Func<T, R> func) 
    where T : Attribute 
    where R : struct 
{ 
    if (a == null) 
     return null; 

    return func(a); 
} 
+0

我認爲可能是這種情況,喬恩。我正在使用表達式樹,因爲這似乎是人們使用lambdas而不是魔術字符串獲取PropertyInfo的最常見方式,並不是因爲我真的瞭解它。如果我答應回去再讀一遍你書中的那一章,你會告訴我一個你現在的意思的例子嗎? ;-) – Colin

+0

@Colin:當然,將編輯該文件。 –

+1

請注意,如果你有這兩個方法,你可以接受任何一個沒有任何約束的方法可以*除了可爲空的struct *的對象。您需要添加第三個重載,其中'T'是一個可以爲空的結構以真正獲取所有內容。 – Servy

相關問題