Общие члены класса в 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', в настоящее время является строкой. Я знаю, что мне кажется, что мне не нужно использовать что -либо, кроме типа строки, но в конце концов я расширирую конструктор, так что «это.
В любом случае, мой компилятор говорит «не может преобразовать« строку »в« t »», поэтому я предполагаю, что делаю что -то очень назад.
Спасибо.
Решение
Ну, какое преобразование вы ожидали от него применить? Если вы ожидаете, что значение уже будет правильного типа, вы можете сделать:
object tmp = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
this.value = (T) tmp;
Обратите внимание, что вам нужно пройти через object
либо неявно (как здесь), либо с явным составом:
this.value = (T)(object) DerivedMethods.configsettings... (etc);
Набор конверсий, предоставленных для общих типов, несколько ограничен. Но это должно работать, если исходное значение действительно верно.
Другие советы
Вы сталкиваетесь с проблемами, потому что это не очень хорошее использование дженериков. Если параметр общего типа может быть построен только четырьмя различными способами - String, Float, Bool и Int - тогда это не очень общий. Анкет Я ожидаю, что общая вещь может быть любой тип вообще.
Если бы у меня была вещь, которая могла бы быть только одним из четырех типов, я бы моделировал это так:
abstract class ConfigSetting
{ /* shared code here */ }
class TextSetting : ConfigSetting
{ /* Code here to handle string settings */ }
class BooleanSetting : ConfigSetting
{ /* ...
и так далее. Я бы, наверное, тогда дал бы каждому из них внутренний конструктор и превратил бы базовый класс в фабрика Для полученных классов, используя заводской шаблон.
Используйте дженерики, только если ваше решение действительно общий. Анкет Нравиться List<T>
, например, может быть список что-либо: ints, струны, массивы, словари, функции, что угодно. Если то, что вы моделируете, имеет небольшое количество возможных типов, просто сделайте один для каждого типа.
Вам нужно бросить возвращенную строку в T
:
public ConfigSetting(string heading, string key) {
this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
}
Я думаю, что вы не обязательно должны использовать дженерики для планирования заранее для всех возможных будущих сценариев, потому что вы, вероятно, столкнетесь с случаями Edge в будущем и независимо от того, чтобы изменить код.
Однако, если у вас уже есть несколько сценариев, к которым подходит универсальный, то вы можете получить выгоду от повторного использования логики и сможете проверить их все правильно.
Я вижу, что другие уже предоставили кодовые ответы, поэтому я остановлюсь здесь.
Я предполагаю, что
DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue
это строка.
Вы не можете назначить строку this.value
Потому что тип this.value
является T
и может быть что угодно, например, типы, на которые строки не назначаются.
Одним из решений является удаление общего параметра и сделать value
Строка, а затем предоставляет различные способы получить доступ к ней, которые разрабатывают Bools, Flow или что -то еще по мере необходимости.
public float GetFloatValue {
get { return float.Parse(this.value); }
}
// etc
Похоже, вы пытаетесь назначить строку (configsettings.SettingGroups[heading].Settings[key].RawValue
) для общего члена. Вам нужно будет предоставить какой -то способ преобразования строки в тип T - обычно через кастинг. Например:
this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
В этой линии:
this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
Вы устанавливаете свою переменную типа T на строковое значение. Метод RawValue возвращает строку. Вам нужно явно поднять его на тип T.
this.value = (T) (object) DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
На самом деле T будут только значениями без конструкторов? Вы можете сделать это явным и избежать объект Кастинг, если вы хотите избежать этого по какой -то причине.
Попробуйте а
string strValue = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
this.value = (T)Convert.ChangeType(strValue, typeof(T), CultureInfo.InvariantCulture)
Если у вас есть значения конфигурации, хранящиеся как строки, и вы хотите преобразовать в правильный тип. Это работает только для большинства примитивных типов, таких как Int32, Double и т. Д.