2010-09-02 3 views
0

Я создал несколько классов, которые будут использоваться для предоставления данных хранимым процедурам в моей базе данных. В varchar параметрах хранимых проков имеют спецификации длины (например, varchar(6), и я хотел бы, чтобы проверить длину всех строковых свойств перед передачей их на хранимые процедуры.Какие способы можно гарантировать, что свойство string имеет определенную длину?

есть простой, декларативный способ сделать это?


у меня есть две концептуальные идеи до сих пор:

Атрибуты

public class MyDataClass 
{ 
    [MaxStringLength = 50] 
    public string CompanyName { get; set; } 
} 

Я не уверен, какие сборки/пространства имен мне нужно будет использовать для реализации такой декларативной разметки. Я думаю, что это уже существует, но я не уверен, где и когда это лучший способ.

Validation в свойствах

public class MyDataClass 
{ 
    private string _CompanyName; 
    public string CompanyName 
    { 
     get {return _CompanyName;} 
     set 
     { 
       if (value.Length > 50) 
        throw new InvalidOperationException(); 
       _CompanyName = value; 
     } 
    } 
} 

Это кажется, что много работы, и будет действительно сделать мои настоящий момент простых классов выглядят довольно некрасиво, но я предполагаю, что это будет получить работу. Это также займет много копий и склеиваний, чтобы получить это право.

+0

'[MaxStringLength (50)]' может даже компилироваться. –

+0

Если вам нужно пойти по маршруту исключения (я не уверен, есть ли альтернатива), [это] (http://blog.getpaint.net/2008/12/06/a-fluent-approach-to -c-parameter-validation /) статья довольно интересная - если вы свободно программируете, то есть. – Stephen

+0

Попробуйте реализовать поведение атрибута, чтобы понять, что действительно выглядит уродливый код. –

ответ

2

Я отправлю это как другой ответ, потому что это характерно отличается от контрактов кода.

One подход, который вы можете использовать, чтобы декларативная проверка заключалась в использовании словаря или хеш-таблицы в качестве хранилища свойств, а также для совместного использования метода полезности для проверки.

Например:

// Example attribute class for MaxStringLength 
public class MaxStringLengthAttribute : Attribute 
{ 
    public int MaxLength { get; set; } 
    public MaxStringLengthAttribute(int length) { this.MaxLength = length; } 
} 

// Class using the dictionary store and shared validation routine. 
public class MyDataClass 
{ 
    private Hashtable properties = new Hashtable(); 

    public string CompanyName 
    { 
     get { return GetValue<string>("CompanyName"); } 

     [MaxStringLength(50)] 
     set { SetValue<string>("CompanyName", value); } 
    } 

    public TResult GetValue<TResult>(string key) 
    { 
     return (TResult)(properties[key] ?? default(TResult)); 
    } 

    public void SetValue<TValue>(string key, TValue value) 
    { 
     // Example retrieving attribute: 
     var attributes = new StackTrace() 
          .GetFrame(1) 
          .GetMethod() 
          .GetCustomAttributes(typeof(MaxStringLengthAttribute), true); 
     // With the attribute in hand, perform validation here... 

     properties[key] = value; 
    } 
} 

Вы можете получить в вызывающей собственности с помощью отражения, работая вашу трассировку стеки, как demonstrated here. Отразите атрибуты свойств, запустите проверку, и voila! Однопользовательские геттер/сеттеры, которые имеют общую процедуру проверки.

На в стороне, эта модель также удобна тем, что вы можете создать класс, чтобы использовать альтернативные словарь, как магазины свойств, такие как ViewState или сессии (в ASP.NET), обновив только GetValue и SetValue.

Еще одно примечание: следует ли использовать этот подход, вы можете рассмотреть возможность реорганизации логики проверки в класс утилиты проверки для совместного использования среди всех ваших типов. Это должно помочь предотвратить слишком большой объем вашего класса данных в методе SetValue.

+0

Спасибо за пример. Мне нравится, как вы показываете использование рефлексии и пользовательский класс MaxStringLength. Это должно дать мне хорошее начало. Я не уверен в использовании хэш-таблицы для свойств, но это неплохая идея. –

+0

Я добавил следующий вопрос об атрибутах: [Использовать отражение, чтобы получить атрибут свойства посредством метода, вызванного из сеттера] (http://stackoverflow.com/questions/3628630/use-reflection-to-get- атрибут-оф-а-свойство-через-метод называемого-из-инкубатора) –

1

Это звучит как деловое правило. Поэтому я бы поместил его в класс компании (так как это имя_компании) и выполнил проверку. Я не понимаю, почему это потребует копирования и вставки, если вы его инкапсулировали.

Любой атрибут или ваш второй пример должны быть точными. Однако атрибут допускает повторное использование в других классах с ограничениями длины строки.

0

Хотя не совсем то же самое, недавно я узнал о .NET 4 Code Contracts в статье MSDN. Они обеспечивают удобный и элегантный способ кодирования и анализа допущений кода. Это стоит взглянуть.

+0

Я немного ознакомился с кодовыми контрактами, но я не смог быстро увидеть, как я могу использовать их для решения моей проблемы. Есть идеи? –

+0

Я думаю, что что-то вроде 'Contract.Requires (value == null || value.Length <50)' будет. Это не идеальный аналог того, что вы пытаетесь выполнить, если я правильно понимаю, поскольку контракты, как представляется, существуют для статической проверки, но могут быть удалены в компиляции. – kbrimington

2

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

Прежде всего, это должно быть [MaxStringLength(50)]. Далее, все, что происходит, это добавление некоторых данных в объект Type для этого класса. Вам все еще нужен способ использования этих данных.

Один из способов был бы двоичным повторителем. После компиляции (но до выполнения), переписывающий будет читать сборку, ища этот атрибут, и, найдя ее, добавьте код для проверки. Розничный продукт PostSharp был разработан, чтобы делать именно этот тип вещей.

Альтернативно, вы можете запустить его во время выполнения. Что-то вроде:

public class MyDataClass 
{ 
    private string _CompanyName; 

    [MaxStringLength(50)] 
    public string CompanyName 
    { 
     get {return _CompanyName;} 
     set 
     { 
      ProcessValidation() 
       _CompanyName = value; 
     } 
    } 
} 

Это все еще довольно некрасиво, но это немного лучше, если у вас есть целый ряд проверки атрибутов.

+0

Код, который вы предоставляете, по крайней мере выглядит лучше, чем мой код, потому что в атрибуте объявлено ограничение проверки. Как «ProcessValidation» видит атрибут «MaxStringLength» и знает, с какими свойствами он работает? –

+0

Отражательно. Метод ProcessValidation() может знать тип вашего объекта (либо this.GetType(), либо аналогичный вызов по переданному параметру), и оттуда он может получать информацию для члена CompanyName и расширять атрибуты, украшающие его.Атрибутом может быть только флаг, указывающий центральной процедуре проверки правильности точных правил для применения, или вы можете поместить правило проверки в атрибут и рефлексивно вызвать некоторый метод Evaluate() для самого атрибута. Декларативная проверка может стать беспорядочной, но этот беспорядок может быть скрыт за кулисами, в отличие от простых членов класса Validate(). – KeithS

1

Первый способ использования атрибута звучит хорошо.

Реализовать свой атрибут по наследованию от Системы.Класс атрибута и отметьте свой класс атрибутом AttributeUsage, чтобы ваш атрибут был установлен в поле.

Затем, используя отражение, проверьте наличие и значение атрибута перед отправкой значения в SP.

Это обеспечивает вам большую гибкость, чем второй метод. Если tomorow вы решите позволить вашему SP получить первые N символов слишком длинной строки, вам не придется изменять весь ваш код, а только тот, который интерпретирует атрибут.

В структуре действительно есть некоторый атрибут проверки, но я бы не использовал их, потому что вы могли бы предполагать какое-то поведение, которого вы не ожидаете, и потому, что вы не сможете каким-либо образом изменить (в любом случае, если вы хочу что-то вроде [MaxLength (50, истинный)], чтобы указать, что с помощью первых 5о символов ОК.

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