开发者

Generic Class Members in C#?

开发者 https://www.devze.com 2022-12-15 17:44 出处:网络
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 somethin

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;
    }
    pub开发者_开发问答lic 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.


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.


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.


You need to cast the returned String to T:

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


I think you shouldn't necessarily use generics to plan ahead for all possible future scenarios because you will likely run into edge cases in the future and have to modify the code regardless.

However if you already have multiple scenarios that a generic would fit to, then you can benefit from the logic reuse now and can test them all properly.

I see others have already provided code answers so I'll stop here.


I assume that

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

is a string.

You can't assign a string to this.value because the type of this.value is T and could be anything, such as types to which strings are not assignable.

One solution is to remove the generic parameter and make value a string, and then provide different ways of accessing it which parse bools, floats, or whatever as required.

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

// etc


It looks like you're trying to assign a string (configsettings.SettingGroups[heading].Settings[key].RawValue) to the generic member. You'll need to provide some way to convert the string to type T -- usually through casting. For example:

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


In this line:

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

you are setting your variable of type T to a string value. The RawValue method returns a string. You need to explicitly cast it to type T.

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

Is T really only going to be only values without constructors? You might be able to make that explicit and avoid the object casting, if you want to avoid that for some reason.


Try a

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

if you have your configuration values stored as strings and want it converted to the right type. This only works for most of the primitive types like Int32, Double, etc.

0

精彩评论

暂无评论...
验证码 换一张
取 消