Общие члены класса в C #? - PullRequest
5 голосов
/ 05 января 2010

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

    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.

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

Спасибо.

Ответы [ 8 ]

7 голосов
/ 05 января 2010

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

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

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

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

class BooleanSetting : ConfigSetting
{ /* ... 

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

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

6 голосов
/ 05 января 2010

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

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

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

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

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

2 голосов
/ 05 января 2010

Вам необходимо привести приведенную строку к T:

public ConfigSetting(string heading, string key) {
    this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
}
1 голос
/ 05 января 2010

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

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

- это строка.

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

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

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

// etc
1 голос
/ 05 января 2010

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

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

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

0 голосов
/ 05 января 2010

Попробуйте

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

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

0 голосов
/ 05 января 2010

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

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

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

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

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

0 голосов
/ 05 января 2010

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

this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...