2010-01-05 4 views
5

Эй, я думаю, что у меня есть неправильная идея, но я не уверен, что лучше. Я хочу класс с переменной-членом, который может быть любого типа, в зависимости от того, что необходимо в то время. До сих пор, у меня есть что-то вроде этого:Общие члены класса в C#?

public class ConfigSetting<T> { 
    private T value; 

    public T GetValue() { 
     return value; 
    } 
    public void ChangeValue() { 

    } 

    public ConfigSetting(string heading, string key) { 
     this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
    } 
} 

Тип возвращаемый справа от «this.value» линии является строкой, в настоящее время. Я знаю, здесь мне кажется, что мне не нужно использовать ничего, кроме типа строки, но в итоге я разберу конструктор, так что «this.value» может быть строкой, int, float или bool.

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

спасибо.

ответ

6

Ну, что преобразование вы ожидаете его применять? Если вы ожидаете, что значение уже быть правильного типа, вы можете сделать:

object tmp = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T) tmp; 

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

this.value = (T)(object) DerivedMethods.configsettings... (etc); 

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

+1

Спасибо. Это компилируется (хотя мне еще предстоит проверить его). У меня есть два вопроса: 1: Зачем мне проходить предмет? 2: Что произойдет после этого, если я попытаюсь использовать методы String по значению? C# теперь знает, что значение имеет тип String? – Xenoprimate

+1

не RawValue всегда возвращает строку? не будет ли преобразование в int, long и т. д.? – bendewey

+0

Да, но, как я уже сказал в своем первоначальном вопросе, я намерен расширить конструктор. – Xenoprimate

2

Вы должны бросить возвращенную строку в T:

public ConfigSetting(string heading, string key) { 
    this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
} 
+0

Это не работает, такая же ошибка. Я бы сказал, что я уже пробовал это, но я догадался, что проблема глубже, чем эта. – Xenoprimate

0

Похоже, вы пытаетесь назначить строку (configsettings.SettingGroups[heading].Settings[key].RawValue) основному члену. Вам нужно будет каким-то образом преобразовать строку в тип T - обычно с помощью кастинга. Например:

this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
0

В этой строке:

this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

вы устанавливаете переменную типа T в строковое значение. Метод RawValue возвращает строку. Вам нужно явно направить его на тип T.

this.value = (T) (object) DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

Действительно ли T это только значения без конструкторов? Возможно, вы сможете сделать это явным и избегать объекта , если вы хотите избежать этого по какой-то причине.

1

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

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

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

1

Я предполагаю, что

DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue 

является строкой.

Вы не можете назначить строку this.value, поскольку тип this.value равен T и может быть любым, например, типами, для которых строки не могут быть назначены.

Одним из решений является удаление общего параметра и создание строки value, а затем предоставление различных способов доступа к ней, которые анализируют bools, floats или что-то еще, что требуется.

public float GetFloatValue { 
    get { return float.Parse(this.value); } 
} 

// etc 
0

Попробуйте

string strValue = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T)Convert.ChangeType(strValue, typeof(T), CultureInfo.InvariantCulture) 

если у вас есть ваши конфигурационные значения хранятся в виде строк и хотите преобразовать в правильный тип. Это работает только для большинства примитивных типов, таких как Int32, Double и т. Д.

7

Вы столкнулись с проблемами, потому что это не очень полезно использование дженериков. Если параметр типового типа может быть построен только четырьмя различными способами: string, float, bool и int - тогда это не очень generic. Я ожидаю, что общая вещь может быть любого типа вообще.

Если бы я была вещь, которая может быть только один из четырех типов, то я бы смоделировать это так:

abstract class ConfigSetting 
{ /* shared code here */ } 

class TextSetting : ConfigSetting 
{ /* Code here to handle string settings */ } 

class BooleanSetting : ConfigSetting 
{ /* ... 

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

Используйте только дженерики, если ваше решение действительно generic. Например, List<T>, может быть список ничего: ints, строки, массивы, словари, функции, что угодно. Если вещь, которую вы моделируете, имеет небольшое количество возможных типов, просто создайте ее для каждого типа.

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