2013-06-20 2 views
1

У меня есть класс, который является сущностью из базы данных, которая имеет кучу дат, представленных в виде строк. Например, это может быть что-то вроде этого:Есть ли способ сделать это валидацию общим?

public class Stuff 
{ 
    public string Date1 {get;set;} 
    public string Date2 {get;set;} 
    public string Date3 {get;set;} 
    public string Date4 {get;set;} 
} 

Я тогда метод проверки, который проверяет другие свойства, а также проверяет свойства даты. В настоящее время я проверяю каждую дату отдельно для каждого объекта. Это работает, но мне было интересно, если бы я мог сделать его общим, поэтому мне не пришлось дублировать код между классами и внутри самого класса. В настоящее время я делаю что-то вроде:

public bool ValidateDate(string date) 
{ 
    string[] overrides = {"","__/__/____"}; 

    bool success = true; 
    DateTime dateTime; 

    if(!overrides.Contains(date) && !DateTime.TryParse(date,out dateTime)) 
    { 
     success = false; 
    } 


    return success; 
} 

//Notice in this method I am repeating the if statements. 
public bool Validate(Stuff stuff, out string message) 
{ 
    message = string.Empty; 
    bool success = true; 

    if(!ValidateDate(stuff.Date1)) 
    { 
     success = false; 
     message = "Date 1 is invalid"; 
    } 

    if(!ValidateDate(stuff.Date2)) 
    { 
     success = false; 
     message = "Date 2 is invalid"; 
    } 

    if(!ValidateDate(stuff.Date3)) 
    { 
     success = false; 
     message = "Date 3 is invalid"; 
    } 

    if(!ValidateDate(stuff.Date4)) 
    { 
     success = false; 
     message = "Date 4 is invalid"; 
    } 

    return success; 
} 

void Main() 
{ 
    string message; 

    Stuff stuff = new Stuff(); 
    stuff.Date1 = "01/01/2020"; 
    stuff.Date2 = "__/__/____"; 
    stuff.Date3 = ""; 
    stuff.Date4 = "44/__/____"; 


    bool valid = Validate(stuff, out message); 

} 

Я думал о делать что-то вроде:

public bool Validate<T>(T value, out string message) 
{ 
    //Validation here 
} 

Но, поправьте меня, если я ошибаюсь, но это потребовало бы, что я получаю свойства и использование отражения в проверьте значение даты и мою другую проблему, так как свойства - это строки, поэтому нет возможности проверить, является ли это DateTime?

+2

Не изобретать колесо, вы должны думать, чтобы использовать 3-ю партию для проверки, как: Свободный валидация или аннотация данных вместо того, чтобы делать вручную –

+0

@CuongLe - Можете ли вы указать на стороннюю библиотеку проверки, которая будет делать это не только для дат, но и для других типов? Вы ссылались на это: http: //fluentvalidation.codeplex.com/ – Xaisoft

+0

Да, это правильно ---- –

ответ

0

Лучшее, что вы можете сделать, вероятно, что-то вроде этого, хотя я не сторонник использования строки для представления дат.

public bool ValidateDates(params string[] dates) 
{ 
    return dates.All(d => ValidateDate(d)); 
} 

public bool Validate(Stuff stuff, out string message) 
{ 

    ValidateDates(stuff.Date1,stuff.Date2,stuff.Date3); 
} 

, очевидно, Вы можете играть с этим, чтобы знать, какая дата не удалось, например, вы можете сделать что-то вроде

var item = dates.Select(d, i => new 
{ 
    Valid = ValidateDate(d), 
    Message = String.Format("Date {0} failed", i) 
}).FirstOrDefault(x => !x.Valid); 

if(item == null) //everything is valid 
    return true; 
else 
    //set the out param 
    outMessageStr = item.Message; 

return false; 
+0

Да, я согласен, хранение дат как строк - не очень хорошая идея. Это было результатом старой базы данных MySQL, предназначенной для некоторых аппаратных систем, и теперь я зациклен на даты как строки. Я не знаком с синтаксисом, начиная с 'var item = date.Select (d, i => .....'. Не могли бы вы объяснить это? – Xaisoft

+0

@Xaisoft Я в основном использую LINQ для итерации по коллекции строк даты (вместо forloop), для каждой даты я создаю анонимный класс, который просто содержит 2 свойства, независимо от того, была ли дата действительной, и это сообщение об ошибке с использованием «i» в качестве индекса, после чего Select run у меня должен быть Enumerable из этих анонимный объект, после которого я просто выбираю FIRST, который НЕ является допустимым ... если все они действительны, у меня просто будет NULL в моей переменной элемента. –

1

Я чувствую, что не хватает какой-то информации - прямо сейчас дублированию, что я см., что вы вызываете ValidateDate несколько раз. Я не думаю, что есть способ обойти это: вам нужно вызвать Validate для каждого свойства Date, если (как вы упомянули) вы не хотите идти по маршруту отражения.

С отражением вы просто перебрать все свойства и найти какое-либо имущество, чье имя соответствует шаблону Date[number], вы бы затем подтвердить, что это действительно DateTimeParse, как вы уже делаете), а затем двигаться дальше.

Если количество полей известно и не слишком много, я бы придерживался вашего ValidateMethod, хотя обратите внимание, что message в настоящее время только покажет вам последнюю ошибку (она перезаписывается каждый раз).

Вы можете получить мило и написать метод, как:

public bool Validate(Stuff stuff, out string message) 
{ 
    message = "Invalid Date(s): "; 

    return ValidateDates(ref message, stuff.Date1, stuff.Date2, stuff.Date3, stuff.Date4); 
} 

public bool ValidateDate(ref string message, params string[] dates) 
{ 
    bool rv = true; 

    for (int i = 0; i < dates.Length; i++) 
    { 
     if (![validate DateTime as above]) 
     { 
      message += i + " "; // add the failed index to the message 
      rv = false; 
     } 
    } 
    return rv; 
} 
+0

Ну, вы правы в том, что я бы прошел через все свойства, но свойство Date не обязательно имеет слово «Date» в его имени, поэтому мне действительно нужно было бы ударить по базе данных и проверить определенную таблицу, которая сообщит мне, является ли свойство датой, и мне было бы неловко сделайте это. – Xaisoft

0

Вы могли сделать все общие с помощью интерфейсов для объектов, которые вы хотите получить от даты.

Например:

//Defines an interface that provides a function to get multiple dates from an object. 
public interface IGetDates 
{ 
    //You could use a Read-Only property too 
    string[] GetDates(); 
} 

public class Stuff : IGetDate 
{ 
    //other stuff... 

    public string[] GetDates() 
    { 
      return new[]{ Date1, Date2, Date2, ect...}; 
    } 
} 

Тогда ваш общий метод будет выглядеть следующим образом:

//Uses generic constraints so only objects that use the 
//IGetDates interface can call this method. 
public bool Validate<T>(T stuff, out string message) where T : IGetDates 
{ 
    message = string.Empty; 
    bool success = true; 
    string[] dates = stuff.GetDates(); 
    for(int i = 0; i < dates.Length; i++) 
    { 
      if(!Validate(dates[i])) 
      { 
       success = false; 
       message = string.Format("Date {0} is invalid.", i); 
      } 
    } 
    return success; 
} 
+0

Мои даты не 'DateTime'. – Xaisoft

+0

Им не обязательно быть, я изменил его. – AtinSkrita

+0

Могу ли я реализовать интерфейс, если 'Stuff' является сущностью? Я имею в виду, что 'Stuff' не является классом POCO, например, это сгенерированный класс сущности, основанный на файле edmx. – Xaisoft

Смежные вопросы