2012-04-03 4 views
2

У меня есть класс, который имеет свойство общего типа, как показано ниже. Тип T может быть любое число (короче говоря, целый, дробный ...)Общий способ обработки чисел без явного преобразования

public class EqualFilter <T> : Filter { 
     private T _value; 
     public override T Value { 
     get { 
      return _value; 
     } 
     set { 
      if (!EqualityComparer<T>.Default.Equals(_value, value)) { 
       _value = value; 
       RaiseFilteringChanged(); 
      } 
     } 
    } 
    ..... 
} 

Теперь у меня есть класс клиента, который имеет «String», который должен быть передан выше сеттера. Теперь, когда вы устанавливаете значение в указанном выше параметре, тип T уже определен во время выполнения, и я могу получить этот тип как тип T в моем клиенте. Можно ли преобразовать строку в соответствующий тип, как определено EqualFilter, в клиентскую программу? Нечто подобное, что не работает

Type T = filter.getFilterType(); 
filter.Value = (T) myTextBox.Text; 

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

Type T = filter.getFilterType(); 
if (T == typeof(int)) { 
    filter.Value = Int32.Parse(myTextBox.Text); 
} else if() { 
.... 
} 

Короче говоря, я не уверен, как лучше подойти к проблеме.

+0

Не можете ли вы поставить ограничение типа на 'T'? http://msdn.microsoft.com/en-us/library/d5x73970.aspx – Bazzz

+0

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

+2

это просто ограничение на типы, которые 'T' принимает. Ваш текущий код принимает 'T' как ЛЮБОЙ тип, вы можете ограничить его определенным интерфейсом и использовать все ваши принятые типы для реализации этого интерфейса. Это немного неудобно с примитивными типами, но «IComparable» может быть хорошим: 'где T: IComparable'. Вам не нужно будет отличать 'T' до фактического типа перед сравнением, потому что EVERY' T', который заканчивается в вашем методе, является 'IComparable', поэтому вы можете смело применить его к' IComparable' и использовать метод 'Compare': '((IComparable) T) .Compare();' а не все ваши разные роли. – Bazzz

ответ

2

Это звучит, как вы делаете что-то похожее на связывание данных. Если все вы заинтересованы в работают со строками, вы могли бы рассмотреть ограничения общего типа для IConvertible и вызов метода Convert.ChangeType из специального метода сеттера, как так:

public class EqualFilter<T> : Filter where T : IConvertible { 

    // ... omitted Value property code ... 

    public void SetValue(string value) 
    { 
     Value = (T)Convert.ChangeType(value, typeof(T)); 
    } 

    // ... 
} 

общих типа разрешений ограничений только те типы, которые Convert.ChangeType может работать. Помимо интегральных и плавающих типов, это также позволяет использовать типы string, decimal и DateTime. Просто имейте в виду, что типы string не всегда могут быть точными при работе с типом double, так как могут быть ошибки округления и с плавающей запятой. Также могут быть и другие исключения, которые вы можете захотеть поймать, чтобы сделать это более надежным (например, FormatException и OverflowException).

void Main() 
{ 
    var a = new EqualFilter<int> { Value = 10 }; 
    var b = new EqualFilter<double> { Value = 20 }; 
    b.Value = Math.PI; // RaiseFilteringChanged called - no surprise 
    b.SetValue(Math.PI.ToString()); // RaiseFilteringChanged called - surprised? 
    Console.WriteLine(b.Value); 
    b.SetValue("25"); 
    Console.WriteLine(b.Value); 
    var c = new EqualFilter<DateTime> { Value = DateTime.Today }; 
    Console.WriteLine(c.Value); 
    c.SetValue("12/23/2011"); 
    Console.WriteLine(c.Value); 

    // compiler error object isn't an IConvertible: 
    // var illegal = new EqualFilter<object>(); 
} 

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

Edit: Добавление Console.WriteLine выхода из моей версии коды выше (то есть переопределение и использование базового класса закомментированного):

3,14159265358979

10/10/2012 12:00:00 AM

12/23/2011 12:00:00 AM

+0

Я получаю Invalid Cast Exception для «Value = (T) Convert.ChangeType (значение, typeof (T));». Строка не может быть преобразована в числовую (int, float, ...) с помощью Convert.ChangeType(). – Jatin

+0

Не могли бы вы опубликовать код, который вы используете? В версии, которую я опубликовал здесь, я восстановил части, которые я прокомментировал, чтобы они были скомпилированы и прошли проверку, без базового класса. Это сработало для меня - недействительный листинг - так что мне интересно, есть ли что-то еще в игре, что может быть очевидно, если вы разместите остальную часть своего кода. – devgeezer

+0

Извините за мой предыдущий комментарий. Ваш код работает хорошо, поэтому я отметил его как ответ. Но если вы можете помочь мне с другой связанной проблемой. Я использую EqualFilter для создания типов EqualFilter , EqualFilter и т. Д. Для всех числовых типов в зависимости от типа моего свойства класса модели. Можно ли обобщить этот экземпляр, так что у меня есть только одна строка эквалайзера EqualFilter <> для всех числовых типов? Аналогично, когда я отбрасываю Filter (базовый класс EqualFilter <>) обратно в EqualFilter, я просто делаю это один раз в своем коде вместо того, чтобы иметь else для каждого типа (int, double и т. Д.). – Jatin

1

Вы можете попробовать следующее:

filter.Value = Convert.ChangeType(myTextBox.Text, filter.getFilterType()); 

Это не будет работать, если преобразование не определено, хотя.

Edit:

Я не заметил ваше Value имущество было общим. Чтобы сделать эту работу вы можете расширить свой объект фильтра, что-то вроде этого:

public object UnsafeValue 
{ 
    set 
    { 
     Value = (T)value; 
    } 
} 

и присвоить результат Convert.ChangeType к этому свойству.

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

+0

@ConvertType возвращает объект, поэтому мне нужно отбросить его до T, а компилятор не позволяет это - «Тип или пространство имен не найдено». – Jatin

+0

@Nirvan: Смотрите мое редактирование. – Nuffin

+0

Сначала казалось перспективным решением, но значение Value = (T) не срабатывает и дает исключение во время выполнения. Я думаю, мне придется пересмотреть подход, возможно, следуя тому, что @Bazz прокомментировал и посмотрел, как это работает. На одном из языков, над которыми я работал, он имеет базовый класс Number, который охватывает все числовые типы. Используя это, было очень легко справиться с ситуацией, в которой я нахожусь. Но тогда у C# есть множество функций, которые отсутствуют на других языках, и я вполне доволен этим. – Jatin

0

Рассматривали ли вы создать конкретный метод установки, как это:

public void setValue(object o){ 
    if (typeof(o) == typeof(Value)) { 
     Value = (typeof(Value))o; 
    } 
} 
+0

Если это сработает, OP не спросил бы в первую очередь. – Nuffin

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