我有幾個類來實現某個接口。如何驗證C#界面字段中的數據?
在接口而不是實現級別的級別上,是否有任何方式來定義數據驗證規則?
如果不是,那麼建議的模式將從特定類中提取數據驗證規則是什麼? (編輯:在我的情況,我想盡量避免使用一個抽象基類來實現驗證。)
謝謝
我有幾個類來實現某個接口。如何驗證C#界面字段中的數據?
在接口而不是實現級別的級別上,是否有任何方式來定義數據驗證規則?
如果不是,那麼建議的模式將從特定類中提取數據驗證規則是什麼? (編輯:在我的情況,我想盡量避免使用一個抽象基類來實現驗證。)
謝謝
我會將驗證邏輯分隔到另一個類中。例如,如果你的界面是IFoo
,你將有一個FooValidator
與Validate(IFoo foo)
方法。這將IFoo
的實現與有關驗證的業務規則分開。分離是指:
IFoo
IFoo
本示例實施使用摘要ValidatorBase
你最初不需要使用的類,我過早地優化它: - $。
interface IFoo
{
int Age { get; }
string Name { get; }
}
class Foo : IFoo
{
public int Age { get; set; }
public string Name { get; set; }
}
abstract class ValidatorBase<T>
{
public class Rule
{
public Func<T, bool> Test { get; set; }
public string Message { get; set; }
}
protected abstract IEnumerable<Rule> Rules { get; }
public IEnumerable<string> Validate(T t)
{
return this.Rules.Where(r => !r.Test(t)).Select(r => r.Message);
}
}
class FooValidator : ValidatorBase<IFoo>
{
protected override IEnumerable<ValidatorBase<IFoo>.Rule> Rules
{
get
{
return new Rule[] {
new Rule { Test = new Func<IFoo,bool>(foo => foo.Age >= 0), Message = "Age must be greater than zero" },
new Rule { Test = new Func<IFoo,bool>(foo => !string.IsNullOrEmpty(foo.Name)), Message = "Name must be provided" }
};
}
}
}
static void Main(string[] args)
{
var foos = new[] {
new Foo { Name = "Ben", Age = 30 },
new Foo { Age = -1 },
new Foo { Name = "Dorian Grey", Age = -140 }
};
var fooValidator = new FooValidator();
foreach (var foo in foos)
{
var messages = fooValidator.Validate(foo);
if (!messages.Any()) Console.WriteLine("Valid");
else foreach (var message in messages) Console.WriteLine("Invalid: " + message);
Console.WriteLine();
}
}
程序運行後給出了這樣的結果:
有效
無效:年齡必須大於零
無效:名稱必須提供無效:年齡必須大於零
也許使用抽象類是「人在中間人」在那裏你可以放置屬性的驗證規則?
你不能在接口級別實現任何代碼 - 所以你不能把驗證登錄到接口。
如果您有驗證框架讀取屬性以執行驗證,則可以向接口成員添加屬性。
要共享驗證代碼只是有單獨的方法,需要接口作爲參數,並在那裏進行驗證,如bool Validate(IMyInterface data){... return true;}
。
是否有可能讓這些類都從一個公共基類派生並在那裏實現驗證邏輯?您可以讓公共基類實現接口,並定義派生類將實現的抽象方法來自定義行爲。
首先你不能在接口本身有任何實現。
如果你有這樣的要求,最好用抽象類。
你沒有提到你是否使用WinForms,WPF等,正如其他人所說,你不能把這段代碼放到實際的接口中。
建議的方法是在基類上實現IDataErrorInfo。
這是有人用MVVM模式在基類實現這個的一個例子:IDataErrorInfo with MVVM
你不必遵循MVVM,但你可以按照他的文章,對WPF實現驗證。
即使如此,它還是有點笨重,因爲您必須在每個屬性中進行工作。你只能通過將這些屬性放入一個通用的基類來解決這個問題。如果你有興趣嘗試類似Castle Windsor和設置AOP,但是我不會推薦將其綁定到部分完成的應用程序中,但有更復雜的方法。
另一種可能性是使用屬性。您可以創建自定義屬性來定義驗證規則
public abstract class ValidationAttribute : Attribute
{
public abstract bool IsValid(object value);
}
public class EvenValidation : ValidationAttribute
{
public override bool IsValid(object value)
{
if (!(value is int))
return false;
return ((int)value) % 2 == 0;
}
}
public interface IFoo
{
[EvenValidation]
int SomeValue { get; }
}
public static class Validator
{
public static bool IsValid(object component, object proposedValue, string property)
{
//Use reflection to look for ValidationAttributes on the property
//Use the ValidationAttribute to validate the proposed value
}
}
這似乎是我的項目的合理解決方案。 (比抽象類方法更重要)。但我不確定你的代碼是如何工作的......如何使用Validator類? – nonot1 2011-02-23 17:33:34
@ nonot1 Validator類提供了一個實用程序來確保給定的屬性是有效的。 你可以用它來輕鬆實現IDataError您的具體實施的IFoo,例如 – cordialgerm 2011-02-23 18:42:10
有趣的問題:是否在「繼承」在類中實現方法的接口方法的屬性? – 2011-02-23 18:56:57
這是一個很好的解決方案。有沒有什麼方法可以將它連接起來,以便可以在屬性集上運行'fooValidator.Validate'? – nonot1 2011-02-24 17:36:39
@ nonot1我真的會在UI層(或MVP表現層)運行驗證,所以假設一個Winforms應用程序,如下所示:'void nameTextBox_changed(..){_foo.Name = this.nameTextBox.Text; this.ShowErrors(_fooValidator.Validate(FOO)); }',而不是試圖通過'foo'本身綁定驗證。非常快速地變得非常混亂。 – 2011-02-24 23:54:55