Generic Class Members in C#? - 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.

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.

Related

C# Is there any better way to use Switch-Case / If-Else on generic types

I am currently trying to get some casting on generic types done.
So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.
For simplicity reasons I will just showcase the use of float, bool and default
The setup looks something like this (where T is a generic type defined by the class itself):
protected T DoStuff(T value)
{
switch (value) {
case float floatValue:
float result = DoFloatStuff(floatValue);
switch (result) {
case T output:
return output;
}
case bool boolValue:
bool result = DoBoolStuff(boolValue);
switch (result) {
case T output:
return output;
}
default:
// return value;
DoRealGenericStuff(value) // Edited, since I just want to sort out some special cases
}
}
Where DoFloatStuff and DoBoolStuff are just methods that have 1 parameter and a return type of their types respectively.
If I don't do it like that (I tried some typeof() casting before), the compiler always complains that it cannot cast from T to float and vice versa, even tho I made sure that would be the case with some Case-Switch / If-Else statements.
Does anybody know some better way to do this?
Thanks in advance,
BOTHLine
Edit:
Since a lot of people said kind of the same thing, that I either shouldn't use generics at all in a case like that or my methods would need to be more generic themselves..
My problem here is that I need to use 3rd party methods to handle the special cases I'm checking for (in this case the float and bool types). For the default case I already handled everything in a generic way. But for some defined types I just can't do that.
So to go a little more in detail why that's the case:
I'm currently working on a Plugin for the "Unity Engine". Unity has built in methods to display types (kind of all primitive types and some Unity-specific types). I have a generic Wrapper class which should be able to contain any types. But then when I want to display the content of that wrapper in the GUI that Unity Editor offers, I have to use the built-in methods to display the primitives (something like UnityEditor.EditrGUI.FloatField()). Without those methods I am never able to display anything.
Anything else which can be broken down to those types can then be displayed in a more generic way.
So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.
That is the wrong idea. It's not the way generics should be used. In such a case, you should use method overloading to create the DoStuff for each type individually:
float DoStuff(float value) {/* float implementation here */}
bool DoStuff(bool value) {/* bool implementation here */}
...
The point of generic is to enable you to write a code that will run the same on different types - so it should either be used where the type itself is irrelevant to the code (like in any generic collection) or can be executed with an interface or a base class all the acceptable types implement (or inherits). At this point, generics is usually only needed when you want a method to return a specific implementation of an interface (or base class).
Let the compiler sort it out for you:
protected void DoStuff(float v){}
protected void DoStuff(int v){}
// and so on
//and finally the default:
protected void DoStuff(object v){}
public void Work(T value)
{
DoStuff(value)
}
This is not the short answer but it's the right way (by many standards). There might be a short answer but, if I were you I wouldn't bother.
This is the smell of a factory pattern. A generic should be, as the name suggests, generic and indifferent to the types if it is you can do something like this.
interface IDoStuffer<T>
{
T DoStuff(T value)
}
class DoStuffFloat : IDoStuff<float>
{
public float DoStuff(float value)
{
//Do your float stuff
}
}
class DoStuffBool : IDoStuff<bool>
{
public bool DoStuff(bool value)
{
//Do your bool stuff
}
}
Then you can have a factory give you a correct implementation
class DoStuffFactory
{
public IDoStuff<T> GetDoStuff<T>()
{
if(typeof(T) == typeof(float))
return new DoStuffFloat();
//And other types
}
}

Implictly casting a dynamic object at runtime

Say I have the following code:
class MyField : DynamicObject
{
public dynamic Value { get; private set; }
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = binder.Type == Value.GetType() ? Value : null;
return result != null;
}
public MyField(dynamic v)
{
Value = v;
}
}
// ...
public static class Program
{
static void doSomething(ulong address) { /* ... */ }
public void Main(string[] args)
{
dynamic field = new MyField((ulong)12345);
doSomething(field); // fails as field is not a ulong.
doSomething((ulong)field); // succeeds as field can be casted to a ulong.
ulong field2 = field; // also succeeds
}
}
Is there a way to get the first call to doSomething to succeed? I'm writing a library to read a particular file format which uses serialized C-style structures; reading the file entails reading these saved structure definitions and then "populating" them with the data contained in the rest of the file. I have a "structure" DynamicObject class (to support dot-notation access) and a "field" DynamicObject class, which is primarily necessary to hold additional information on the contents of the field; although I could probably get rid of it, it would make certain other operations more difficult. What I'd like to do is just "pretend" MyField is a certain type (well, technically just any built-in primitive or array of primitives, including 2D arrays) and implicitly convert it to that type. However, the runtime fails to try to implicitly convert field to the type required by the underlying method signature if field doesn't match the type required.
In the vein of Greg's answer, I came up with a solution that makes the runtime happy. It's not exactly what I was originally looking for, but it seems like the best solution.
Since I already have a large if-else tree in my source wherein I take an array of bytes and interpret them as an actual value-type, and indeed my current source does use an underlying generic MyField<T>, so this works fine. I can't recall why I wanted MyField to be dynamic in the first place.
Anyway, this is a modified solution.
class MyField<T>
{
public dynamic Value { get; private set; }
public MyField(dynamic v) { Value = v; }
public static implicit operator T(MyField field)
{
return (T)field.Value;
}
}
I keep coming back to wanting the runtime to just figure out what it needs to cast MyField to at runtime but I guess it's not that big of a deal. If anyone comes up with something better, let me know. I'm going to keep this question open in the meantime.
You potentially might want to look into Generics. Coupled with an interface may make the dynamic usage far more viable.
public interface Helper <TInput, TOutput>
{
<TOutput> DoSomething(TInput input);
}
So when you use this interface with a class, you'll implement your type for both input and output. Which will give you quite a bit of flexibility, which should avoid those cast that you mentioned earlier. A small example, I mean you could obviously adjust it based on needs but I still don't understand what you're trying to really do.

C# Generic method return values

I'm just learning about generics and have a question regarding method return values.
Say, I want a generic method in the sense that the required generic part of the method signature is only the return value. The method will always take one string as it's parameter but could return either a double or an int. Is this possible?
Effectively I want to take a string, parse the number contained within (which could be a double or an int) and then return that value.
Thanks.
Something like this?
void Main()
{
int iIntVal = ConvertTo<int>("10");
double dDoubleVal = ConvertTo<double>("10.42");
}
public T ConvertTo<T>(string val) where T: struct
{
return (T) System.Convert.ChangeType(val, Type.GetTypeCode(typeof(T)));
}
You cannot return either a double or an int from a generic method without it also returning any other type.
I might, for example, have a Foo class and your generic parse method, without any constraint, will allow this call to be made:
Foo result = Parse<Foo>("111");
The best that you can do with numbers is constrain on your function by only allowing struct (value-types) to be used.
T Parse<T>(string value) where T : struct;
But this will allow all number types, plus any other value-type.
You can constrain by interface type, but there isn't an INumeric interface on double or int so you're kind of stuck.
The only thing that you can do is throw an exception if the wrong type is passed in - which generally isn't very satisfying.
Your best approach, in this case, is to abandon generics and use separately named methods.
double ParseDouble(string value);
int ParseInteger(string value);
But, of course, this won't help you learn generics. Sorry.
Yes it's possible.
Example:
public T ParseValue<T>(String value) {
// ...
}
You could do something like ...
public TResult Parse<TResult>(string parameter)
{
/* do stuff */
}
And use it like ...
int result = Parse<int>("111");
And then it will depend on your implementation in the Parse method.
Hope it helps.

Operator as and generic classes

I want to make a method:
object Execute()
{
return type.InvokeMember(..);
}
to accept a generic parameter:
T Execute<T>()
{
return Execute() as T;
/* doesn't work:
The type parameter 'T' cannot be used with the 'as' operator because
it does not have a class type constraint nor a 'class' constraint */
// also neither typeof(T), nor T.GetType() are possible
return (T) Execute(); // ok
}
But I think operator as will be very useful: if result type isn't T method will return null, instead of an exception! Is it possible to do?
You need to add
where T : class
to your method declaration, e.g.
T Execute<T>() where T : class
{
By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:
MyClass c = whatever.Execute() as MyClass;
Or if they want to throw on fail:
MyClass c = (MyClass)whatever.Execute();
The generic wrapper method looks like this:
MyClass c = whatever.Execute<MyClass>();
All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.
(This may be irrelevant to you if your example is simplified from your actual code).
You cannot use the as operator with a generic type with no restriction. Since the as operator uses null to represent that it was not of the type, you cannot use it on value types. If you want to use obj as T, T will have to be a reference type.
T Execute<T>() where T : class
{
return Execute() as T;
}
This small piece of code is an exception safe substitution for the as-keyword:
return Execute() is T value ? value : default(T)
It uses the pattern matching feature introduced with C# 7.
Use it, if you don't want to restrict the generic parameter to a reference type
It seems like you are just adding a wrapper method for casting to the type the user wants, thus only adding overhead to the execution. For the user, writing
int result = Execute<int>();
isn't much different from
int result = (int)Execute();
You can use the out modifier to write the result into a variable in the caller's scope, and return a boolean flag to tell whether it succeeded:
bool Execute<T>(out T result) where T : class
{
result = Execute() as T;
return result != null;
}
Is there a chance that Execute() might return a value type? If so, then you need Earwicker's method for class types, and another generic method for value types. Might look like this:
Nullable<T> ExecuteForValueType<T> where T : struct
The logic inside that method would say
object rawResult = Execute();
Then, you'd have to get the type of rawResult and see if it can be assigned to T:
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
Finally, make your original Execute message figure out which T is has (class or struct type), and call the appropriate implementation.
Note: This is from rough memory. I did this about a year ago and probably don't remember every detail. Still, I hope pointing you in the general direction helps.

Generic type checking

Is there a way to enforce/limit the types that are passed to primitives? (bool, int, string, etc.)
Now, I know you can limit the generic type parameter to a type or interface implementation via the where clause. However, this doesn't fit the bill for primitives (AFAIK) because they do not all have a common ground (apart from object before someone says! :P).
So, my current thoughts are to just grit my teeth and do a big switch statement and throw an ArgumentException on failure.
EDIT 1:
Just to clarify:
The code definition should be like this:
public class MyClass<GenericType> ....
And instantiation:
MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)
EDIT 2
#Jon Limjap - Good point, and something I was already considering. I'm sure there is a generic method that can be used to determine if the type is of a value or reference type.
This could be useful in instantly removing a lot of the objects I don't want to deal with (but then you need to worry about the structs that are used such as Size ). Interesting problem no? :)
Here it is:
where T: struct
Taken from MSDN.
I'm curious. Could this be done in .NET 3.x using extension methods? Create an interface, and implement the interface in the extension methods (which would probably be cleaner than a bit fat switch). Plus if you then need to later extend to any lightweight custom types, they can also implement the same interface, with no changes required to the base code.
What do you guys think?
The sad news is I am working in Framework 2!! :D
EDIT 3
This was so simple following on from Jon Limjaps Pointer.. So simple I almost want to cry, but it's great because the code works like a charm!
So here is what I did (you'll laugh!):
Code added to the generic class
bool TypeValid()
{
// Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));
// All of the TypeCode Enumeration refer Primitive Types
// with the exception of Object and Empty (Null).
// Since I am willing to allow Null Types (at this time)
// all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
}
Then a little utility method to check the type and throw an exception,
private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
}
All that then needs to be done is to call EnforcePrimitiveType() in the classes constructors. Job done! :-)
The only downside, it only throws an exception at runtime (obviously) rather than design time. But that's no big deal and could be picked up with utilities like FxCop (which we don't use at work).
Special thanks to Jon Limjap on this one!
public class Class1<GenericType> where GenericType : struct
{
}
This one seemed to do the job..
Primitives appear to be specified in the TypeCode enumeration:
Perhaps there is a way to find out if an object contains the TypeCode enum without having to cast it to an specific object or call GetType() or typeof()?
Update It was right under my nose. The code sample there shows this:
static void WriteObjectInfo(object testObject)
{
TypeCode typeCode = Type.GetTypeCode( testObject.GetType() );
switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;
case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;
default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
}
It's still an ugly switch. But it's a good place to start!
Pretty much what #Lars already said:
//Force T to be a value (primitive) type.
public class Class1<T> where T: struct
//Force T to be a reference type.
public class Class1<T> where T: class
//Force T to be a parameterless constructor.
public class Class1<T> where T: new()
All work in .NET 2, 3 and 3.5.
If you can tolerate using factory methods (instead of the constructors MyClass you asked for) you could always do something like this:
class MyClass<T>
{
private readonly T _value;
private MyClass(T value) { _value = value; }
public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
// etc for all the primitive types, or whatever other fixed set of types you are concerned about
}
A problem here is that you would need to type MyClass<AnyTypeItDoesntMatter>.FromInt32, which is annoying. There isn't a very good way around this if you want to maintain the private-ness of the constructor, but here are a couple of workarounds:
Create an abstract class MyClass. Make MyClass<T> inherit from MyClass and nest it within MyClass. Move the static methods to MyClass. This will all the visibility work out, at the cost of having to access MyClass<T> as MyClass.MyClass<T>.
Use MyClass<T> as given. Make a static class MyClass which calls the static methods in MyClass<T> using MyClass<AnyTypeItDoesntMatter> (probably using the appropriate type each time, just for giggles).
(Easier, but certainly weird) Make an abstract type MyClass which inherits from MyClass<AnyTypeItDoesntMatter>. (For concreteness, let's say MyClass<int>.) Because you can call static methods defined in a base class through the name of a derived class, you can now use MyClass.FromString.
This gives you static checking at the expense of more writing.
If you are happy with dynamic checking, I would use some variation on the TypeCode solution above.
You can simplify the EnforcePrimitiveType method by using typeof(PrimitiveDataType).IsPrimitive property. Am I missing something?
#Rob, Enum's will slip through the TypeValid function as it's TypeCode is Integer. I've updated the function to also check for Enum.
Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)
' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function
Having a similar challenge, I was wondering how you guys felt about the IConvertible interface. It allows what the requester requires, and you can extend with your own implementations.
Example:
public class MyClass<TKey>
where TKey : IConvertible
{
// class intentionally abbreviated
}
I am thinking about this as a solution, all though many of the suggested was part of my selection also.
My concern is - however - is it misleading for potential developers using your class?
Cheers - and thanks.
Use a custom FxCop rule that flags undesirable usage of MyClass<>.
In dotnet 6, I encountered this error when using struct:
The type 'string' must be a non-nullable value type in order to use it as parameter 'T'
So I use IConvertible instead
var intClass = new PrimitivesOnly<int>();
var doubleClass = new PrimitivesOnly<double>();
var boolClass = new PrimitivesOnly<bool>();
var stringClass = new PrimitivesOnly<string>();
var myAwesomeClass = new PrimitivesOnly<MyAwesomeClass>(); // illegal
// The line below encounter issue when using "string" type
// class PrimitivesOnly<T> where T : struct
class PrimitivesOnly<T> where T : IConvertible
{
}
class MyAwesomeClass
{
}

Categories