2012-11-06 134 views
1

我想在類中進行一些驗證,所以我想我可以使用屬性。 像這樣:獲得屬性修飾屬性的值

public class someClass 
{ 
    [Lenght(200)] 
    public string someStr { get; set; } 
} 
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] 
sealed class Lenght : Attribute 
{ 
    public Lenght(int Lenght) 
    { 
     //some code 
    } 
} 

但我知道,我不能這樣做,因爲這不是屬性如何工作。而且,如果有辦法,它會使用我想避免的某種沉重的反射和雜物。

我想要做的驗證是這樣的:

public class someClass 
{ 

    public string someStr 
    { 
     get 
     { 
      return _someStr; 
     } 
     set 
     { 
      if (value.Length > 200) 
      { 
       throw new Exception("Max Length is 200!"); 
      } 
      else _someStr = value; 
     } 
    } 
    private string _someStr { get; set; } 
} 

但我想做得更快,沒有所有這些代碼。我想和使用屬性一樣快。

有一種方法可以做到這一點?

回答

1

通常你不會做這樣的東西用屬性,但它是可能的,儘管不可取。使用您自己的風險:)(你會放開地獄,如果物業不與LengthAttribute :)飾)

public interface AttributeValidator 
    { 
     void CheckOk(object value); 
    } 

    public class LenghtAttribute : Attribute, AttributeValidator 
    { 
     public int MaxLength { get; private set; } 
     public LenghtAttribute(int lenght) 
     { 
      this.MaxLength = lenght; 
     } 

     public void CheckOk(object value) 
     { 
      var str = value as string; 
      if (str != value) 
       throw new Exception("Not a string!"); 

      if (str != null && str.Length > MaxLength) 
       throw new Exception("To long!"); 
     } 
    } 

    public class DoesNotContain : Attribute, AttributeValidator 
    { 
     public string Chars { get; private set; } 
     public DoesNotContain(string chars) 
     { 
      this.Chars = chars; 
     } 

     public void CheckOk(object value) 
     { 
      var str = value as string; 
      if (str != value) 
       throw new Exception("Not a string!"); 

      if (str != null && Chars.Any(c => str.Contains(c))) 
       throw new Exception("Contains forbidden character!"); 
     } 
    } 

    public class SomeClass 
    { 
     private string _someString; 

     [Lenght(200)] 
     [DoesNotContain("$#2")] 
     public string SomeString 
     { 
      get { return _someString; } 
      set 
      { 
       Utils.Validate("SomeString", this, value); 
       _someString = value; 
      } 
     } 
    } 

    public static class Utils 
    { 
     public static void Validate(string property, object instance, string value) 
     { 
      var validators = instance.GetType().GetProperty(property) 
       .GetCustomAttributes(false).OfType<AttributeValidator>(); 

      foreach (var validator in validators) 
       validator.CheckOk(value); 
     } 
    } 

編輯我已經擴展的例子。仍然是一個可怕的解決方案,但它的工作。

+0

我發佈這個問題已經有2年了,今天我在這裏回顧我的問題。 從那時起我已經學會了一些C#,現在我不會問這個問題,我也不會使用屬性來驗證它。 我接受了你的答案,因爲你付出了一些努力,我只想指出你在SomeClass中的代碼幾乎和我在我的問題中發佈的一樣,但是無論如何。 另外,在對房產驗證有一些經驗後,我再也不想這樣做了,我從不期望在屬性中拋出異常。自那以後,我徹底改變了主意。 –

1

屬性的目的是向其他組件,工具,編譯器等聲明關於程序集,類型,成員,參數等的元數據。當然,你可以做你正在問的東西,但這會涉及到反思自己這是一個很長的路要走,只是像你在第二個例子中那樣堅持價值。

您應該考慮的是一個驗證框架,它爲您提供了所有這些內置功能,並允許您單獨驗證和外部驗證。

有許多驗證框架可供選擇。我頭上兩個受歡迎的人是FluentValidation和企業圖書館的Validation Application Block

另一方面,也許你只是在尋找一個好的Guard類或Code Contracts。這些服務的用途與驗證不同(參見Design by Contract)。你可以想象地將屬性(我建議重用Data Annotations)和一些面向方面的編程結合起來,以聲明方式爲你完成守衛任務(見PostSharp)。但是,這可能只是炫耀:)。

+0

這個FluentValidation框架看起來很有趣,但我不喜歡這個基本驗證使用框架的想法......但它似乎很有趣... –

1

你可以創建這需要的字段作爲ref參數的方法:

public static void SetWithMaxLength(ref string field, string value, int maxLength) 
{ 
    if(value.Length > maxLength) throw new Exception("Max length is " + maxLength); 
    field = value; 
} 

,那麼你可以寫你的setter方法爲:

set 
{ 
    SetWithMaxLength(ref this._someStr, value, 200); 
} 
+0

是的,我可以學習更多關於參考和出參數...謝謝! –