Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Class Members in C#?

Hey, I think I have the wrong idea here, but I'm not sure what is best. I want a class with a member variable that can be of any type, depending on what is needed at the time. So far, I have something like this:

    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;
    }
}

The type returned by the right side of the 'this.value' line is a string, currently. I know here it seems like I have no need to use anything other than the string type, but eventually I will expand the constructor, such that 'this.value' could be a string, int, float, or bool.

Anyway, my compiler says "Cannot convert 'string' to 'T'", so I assume I'm doing something very backwards.

Thank you.

like image 543
Xenoprimate Avatar asked Jan 05 '10 15:01

Xenoprimate


2 Answers

You're running into problems because this is not a good use of generics. If the generic type parameter can only be constructed in four different ways -- string, float, bool and int -- then this isn't very generic. I expect that a generic thing can be any type at all.

If I had a thing that could only be one of four types then I would model it like this:

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

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

class BooleanSetting : ConfigSetting
{ /* ... 

and so on. I would probably then give each of them an internal constructor, and make the base class into a factory for the derived classes, using the factory pattern.

Only use generics if your solution is truly generic. Like List<T>, for example, can be a list of anything: ints, strings, arrays, dictionaries, functions, whatever. If the thing you are modeling has a small number of possible types, just make one for each type.

like image 119
Eric Lippert Avatar answered Sep 29 '22 21:09

Eric Lippert


Well, what conversion did you expect it to apply? If you expect the value to already be of the right type, you could do:

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

Note that you have to go through object either implicitly (as here) or with an explicit cast:

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

The set of conversions provided for generic types is somewhat limited. But it should work if the original value is genuinely correct.

like image 25
Jon Skeet Avatar answered Sep 29 '22 19:09

Jon Skeet