Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Object with field that can be any type

0 views
Skip to first unread message

Cralis

unread,
Jul 20, 2010, 5:04:14 AM7/20/10
to
Hi guys,

I have an object:

class myParameter
{
public string Name {get; set;}
public int ParameterType {get; set;}
public object value {get; set;}
}

What I am currently doing, and probably wrongly so, is storing my
value as an object. The value is determined by the value type. Value
types are String, GPSCoord, Float, Int.. and efw others.

Instead of object, is there a better way to do what I am doing? I'm
thinking Generics, but not sure how this can be done.

So, when I create my object, I do:

myParameter param1 = new myParameter();
param.Name = "Something";
param.ParameterType = 1; // I actually use an enum...
param.value = 5.7;

myParameter param2 = new myParameter();
param2.Name = "Something Else";
param2.ParameterType = 2; // I actually use an enum...
param2.value = "Test String";

Peter Duniho

unread,
Jul 20, 2010, 5:23:16 AM7/20/10
to
Cralis wrote:
> Hi guys,
>
> I have an object:
>
> class myParameter
> {
> public string Name {get; set;}
> public int ParameterType {get; set;}
> public object value {get; set;}
> }
>
> What I am currently doing, and probably wrongly so, is storing my
> value as an object. The value is determined by the value type. Value
> types are String, GPSCoord, Float, Int.. and efw others.
>
> Instead of object, is there a better way to do what I am doing? I'm
> thinking Generics, but not sure how this can be done.

Generic, or inheritance, or both may be the appropriate solution for
your code. It's hard to say for sure without knowing more about what
the rest of the code looks like.

Generics:

class MyParameter<T>


{
public string Name { get; set; }
public int ParameterType { get; set; }

public T Value { get; set; }
}

Inheritance:

class MyParameterBase


{
public string Name { get; set; }
public int ParameterType { get; set; }
}

class MyStringParameter : MyParameterBase
{
public string Value { get; set; }
}

class MyFloatParameter : MyParameterBase
{
public float Value { get; set; }
}

// etc.

Both:

class MyParameterBase<T>


{
public string Name { get; set; }
public int ParameterType { get; set; }

public T Value { get; set; }
}

class MyStringParameter : MyParameterBase<string>
{ }

class MyFloatParameter : MyParameterBase<float>
{ }

// etc.

Using inheritance (either version) allows you to ignore the
type-specific aspects in any code where that doesn't matter. Otherwise,
you have to declare a variable specific to the type of the value to use
the instance. With the generics-only approach, you always have to do
that no matter what, even when you don't really care what the type of
the value property is.

With either of the inheritance versions, you may also find a factory
method/methods in the base class helpful/desirable. An overloaded
factory method can return the derived class of the appropriate type,
depending on the parameter type, which may simplify the code where
instances of these objects are created.

Note that in any of the three above approaches, technically you don't
need the "ParameterType" property, because the actual type of the
property is inherent in the instance type. It's always possible to
determine the actual type of the value simply by looking at that, rather
than a separate property to tell you the same information.

Pete

Cralis

unread,
Jul 20, 2010, 7:56:22 AM7/20/10
to
Thanks again, Pete.

With the inheritance route...
I create a Base class ith all common properties. Call it MyClassBase.

I then have a class called MyClassString : MyClassBase with just the
string value... and one called MyClassInt : MyClassBase.

Now, I am accepting data from the device... INTs and STRINGs...

I need to keep a List<???>. How do I create a list of different object
types?

So, I do a:
List<MyClassBase> myList = new List<MyClassBAse>();

MyClassString o = new MyClassString();
...populate properties...

myList.Add(o);

How would I be able to add both (or all types) of classes in my list?
As I have to define a type?

Peter Duniho

unread,
Jul 20, 2010, 11:36:38 AM7/20/10
to
Cralis wrote:
> [...]

> I need to keep a List<???>. How do I create a list of different object
> types?
>
> So, I do a:
> List<MyClassBase> myList = new List<MyClassBAse>();
>
> MyClassString o = new MyClassString();
> ...populate properties...
>
> myList.Add(o);
>
> How would I be able to add both (or all types) of classes in my list?
> As I have to define a type?

Just as you show above. A List<MyClassBase> can contain any sub-classes
of MyClassBase.

Note that you cannot mix-and-match List<T> types. That is, you can
assign a List<MyClassString> to a List<MyClassBase> variable. But it
doesn't sound like you want to do that. Storing MyClassString instances
in a List<MyClassBase> should work fine.

Pete

Peter Duniho

unread,
Jul 20, 2010, 11:58:14 AM7/20/10
to
Peter Duniho wrote:
> Note that you cannot mix-and-match List<T> types. That is, you can
> assign a List<MyClassString> to a List<MyClassBase> variable.

Typo: the above should read "…you CAN'T assign a List<MyClassString>…"

Sorry if that confused things.

Mark

unread,
Jul 20, 2010, 2:25:45 PM7/20/10
to

Cralis,

There is nothing wrong with storing an object in your class. I would
implement IDisposable and make sure you clear the object of any data.

When accessing the "value" you can simply ask the object for its type
for processing later. The whole point of "object" is that you can do
whatever you want.

Peter Duniho

unread,
Jul 20, 2010, 2:29:14 PM7/20/10
to
Mark wrote:
> There is nothing wrong with storing an object in your class. I would
> implement IDisposable and make sure you clear the object of any data.

There is absolutely nothing about the code here that suggests
IDisposable would be in any way useful.

> When accessing the "value" you can simply ask the object for its type
> for processing later. The whole point of "object" is that you can do
> whatever you want.

The whole point of having a strongly-typed property is that you can only
put the right kind of data in it, and you can write code that at
compile-time already knows the correct type of the property.

Pete

Mark

unread,
Jul 20, 2010, 3:21:23 PM7/20/10
to

> There is absolutely nothing about the code here that suggests
> IDisposable would be in any way useful.

Orly??

object should suggest it... since he did not provide every single
possible assignment that could go in to "object." It would be
suggested that you might have an object that would need to do some
clean up before myParameter was itself disposed.

>
> > When accessing the "value" you can simply ask the object for its type
> > for processing later. The whole point of "object" is that you can do
> > whatever you want.
>
> The whole point of having a strongly-typed property is that you can only
> put the right kind of data in it, and you can write code that at
> compile-time already knows the correct type of the property.
>

There is nothing wrong with using "object" in his example which is
what he asked.

Peter Duniho

unread,
Jul 20, 2010, 4:05:41 PM7/20/10
to
Mark wrote:
>> There is absolutely nothing about the code here that suggests
>> IDisposable would be in any way useful.
>
> Orly??
>
> object should suggest it...

No, "object" doesn't suggest it at all.

> since he did not provide every single
> possible assignment that could go in to "object." It would be
> suggested that you might have an object that would need to do some
> clean up before myParameter was itself disposed.

Why would "myParameter" ever be disposed? It doesn't implement
IDisposable, nor has any reason to.

>>> When accessing the "value" you can simply ask the object for its type
>>> for processing later. The whole point of "object" is that you can do
>>> whatever you want.
>> The whole point of having a strongly-typed property is that you can only
>> put the right kind of data in it, and you can write code that at
>> compile-time already knows the correct type of the property.
>
> There is nothing wrong with using "object" in his example which is
> what he asked.

You mean other than the fact that his question is _specifically_ about
how to avoid using just "object". Though, even if that's what you meant
(which would be odd, since it necessarily takes the discussion in the
opposite direction the OP was intending), it's still not true, since the
lack of strong typing is in fact a very clear and specific thing that is
wrong with using "object".

Sometimes "object" is the right type to use. But when it's possible to
use a more-derived type, one should. Otherwise, why wouldn't we just
declare everything as "object"?

Pete

Mark

unread,
Jul 20, 2010, 4:12:03 PM7/20/10
to

Point taken and I agree on a more derived type. I was not arguing that
he should use object... I was suggesting that disposing might be a
good idea since we don't know what might be stored should the OP keep
"object"... without knowing exactly what the OP is doing it was merely
a suggestion. And of course it is always a good idea to clean up no
matter which way you go.

Peter Duniho

unread,
Jul 20, 2010, 4:30:13 PM7/20/10
to
Mark wrote:
> [...] I was suggesting that disposing might be a

> good idea since we don't know what might be stored should the OP keep
> "object"... without knowing exactly what the OP is doing it was merely
> a suggestion. And of course it is always a good idea to clean up no
> matter which way you go.

What would you do to "clean up" the "myParameter" type? Let's assume
you do implement IDisposable. What would you put into the Dispose()
method? How would that make the code better?

Pete

Cralis

unread,
Jul 20, 2010, 5:19:50 PM7/20/10
to
Thanks guys.

I'm not totally against the idea of staying with an object, but do
undertand Peters concerns, and if there is a way to strongly type.. it
might be better and safer. However, as I say, If I can keep the object
type safely, I may concider that.

Peter, at the moment, using the object type, here's mode code:
(All Parameter values arrives as strings from the device. i.e
parameterValie, parameterName etc etc)

ConfigurationOption option = new ConfigurationOption();
option.OriginalValue = parameterValue;
option.Value = option.OriginalValue;
option.Name = parameterName;
option.ValueType = (ConfigOptionValueType) int.Parse(parameterType);
option.Description = parameterDescription;

So, I just assign them all as Objects, and then later, when I need to
display them or work with them, I check ValueType and then handle the
types there.

All the objects then get assigned to a List<ConfigurationOption>

So... if went the Inheritance route... I would end up with a base
class, as we said before, and a few sub classes. Does that mean I
would end up with a few different lists? Above, you suggest I can't
stay with one list:

--Note that you cannot mix-and-match List<T> types. That is, you
can't
--assign a List<MyClassString> to a List<MyClassBase> variable. But
it
--doesn't sound like you want to do that. Storing MyClassString
instances
--in a List<MyClassBase> should work fine.

Would I therefore need a List<> for each subclass? Or am I right in
saying that I can do this:

Create a MyBaseClass with all common fields.
Create a MyStringClass : MyBaseClass, with:
string value;
Create a MyIntClass : MyBaseClass, with:
int value;
Create a MyFloatClass : MyBaseClass, with:
float value;

List<MyBaseClass> theList = new List<MyBaseClass>();

// Check what the parameterType would be based on the incoming data...
// If it's a string...

MyStringClass option = new MyStringClass(); // Or should this be 'new
MyBaseClass()' ?

option.OriginalValue = parameterValue;
option.Value = option.OriginalValue;
option.Name = parameterName;
option.Description = parameterDescription;
option.Value = parameterValue;

theList.Add(option);

Get next parameter from device...
// Check what the parameterType would be based on the incoming data...
// If it's a float...

MyFloatClass option = new MyFloatClass(); // Or should this be 'new
MyBaseClass()' ?

option.OriginalValue = parameterValue;
option.Value = option.OriginalValue;
option.Name = parameterName;
option.Description = parameterDescription;
option.Value =float.parse(parameterValue,
CultureInfo.InvariantCulture);

theList.Add(option);

Is that right? Or do I need multiple lists?

Cralis

unread,
Jul 20, 2010, 5:21:10 PM7/20/10
to
I wish Google Groups had code colouring and bold.. etc. WOuld make it
easier for you to read... Hope the above post is OK. (And again,
thanks for your time in assisting me here).

Peter Duniho

unread,
Jul 20, 2010, 5:56:23 PM7/20/10
to

It's just as well Google Groups doesn't. I read everything as plain
text, using a regular newsreader. Rich-text formatting would be wasted
on me anyway.

What would be better is to write the code in a easier-to-read format.
Try to provide context, such as methods or even classes to contain the
code examples, and make sure the code is indented and otherwise
formatted nicely.

Pete

Cralis

unread,
Jul 20, 2010, 5:58:47 PM7/20/10
to

Mark

unread,
Jul 20, 2010, 6:12:10 PM7/20/10
to
>
> What would you do to "clean up" the "myParameter" type?  Let's assume
> you do implement IDisposable.  What would you put into the Dispose()
> method?  How would that make the code better?
>
> Pete

public void Dispose()
{
if (value != null && value is IDisposable)
{
((IDisposable)value).Dispose();
}
}

Peter Duniho

unread,
Jul 20, 2010, 6:26:40 PM7/20/10
to
Cralis wrote:
> Thanks Pete..
> Do you need more info then?

It takes longer to respond to posts with specific questions and details
than generalities. I'll get around to it. :)

Peter Duniho

unread,
Jul 20, 2010, 6:29:49 PM7/20/10
to

None of the types that the OP proposed putting in the property implement
IDisposable. More importantly, it makes no sense for code that keeps
references via "object"-typed variables to go around inspecting them to
see if they implement IDisposable, especially when they otherwise would
not themselves need to implement IDisposable.

By the above reasoning, ArrayList, List<T>, and any number of other .NET
types should implement IDisposable and should attempt to dispose every
element in the collection when their IDisposable.Dispose()
implementation is called.

No. When you write general-purpose classes, it is _not_ reasonable to
include the kitchen sink. You put the things into it that are
specifically needed, and only those things.

Pete

Peter Duniho

unread,
Jul 20, 2010, 6:34:01 PM7/20/10
to
Cralis wrote:
> [...]

> So... if went the Inheritance route... I would end up with a base
> class, as we said before, and a few sub classes. Does that mean I
> would end up with a few different lists? Above, you suggest I can't
> stay with one list:

No, that's not what my post suggests.

> --Note that you cannot mix-and-match List<T> types. That is, you can't
> --assign a List<MyClassString> to a List<MyClassBase> variable. But it
> --doesn't sound like you want to do that. Storing MyClassString instances
> --in a List<MyClassBase> should work fine.

The above text means you can't do this:

List<MyClassString> list1 = new List<MyClassString>();

list1.Add(new MyClassString("foo"));

List<MyClassBase> list2 = list1;

That would be illegal, and for good reason.

But there's no problem doing this:

List<MyClassBase> list1 = new List<MyClassBase>();

list1.Add(new MyClassString("foo"));

In fact, that's a very reasonable use of inheritance and the List<T> class.

So, no. You wouldn't need multiple lists.

Pete

Mark

unread,
Jul 20, 2010, 11:41:39 PM7/20/10
to

Okie dokie

Cralis

unread,
Jul 21, 2010, 8:35:16 AM7/21/10
to
I started converting my stuff... but hit a snag, and not sure hwo to
get around it...

I have a method that gets the value, based on a name. So, I search the
objects and get the value, where the name matches an input name:

public string GetParamValue(string value)
{
return _configOptions.Where(e => e.Name ==
value).Select(d => d.Value).FirstOrDefault().ToString();

}

However, configOptions holds a list of the base types. The base type
doesn't have a 'value', as that is held in the sub class.

Peter Duniho

unread,
Jul 21, 2010, 12:52:48 PM7/21/10
to

Note that the method you wrote, GetParamValue(), has a return type of
"string". Thus, to me it only makes sense to examine objects that have
a Value property having the type String.

So, IMHO a better implementation would look something like this:

public string GetStringParamValue(string name)
{
MyClassString result = _configOptions.OfType<MyClassString>()
.Where(x => x.Name == value).FirstOrDefault();

return result.Value;
}

If you really always want to be able to return a string value from _any_
of your config data classes, then you should include that in the base
class definition:

abstract class MyClassBase


{
public string Name { get; set; }

public abstract string ValueString { get; }
}

class MyClassFloat : MyClassBase


{
public float Value { get; set; }

public override string ValueString { get { return Value.ToString(); } }
}

Then you can just write your original method like this:

public string GetParamValue(string value)
{
MyClassBase result = _configOptions.Where(e => e.Name ==
value).FirstOrDefault();

if (result != null)
{
return result.ValueString;
}

return null;
}

(Note that your original implementation has a bug, in that you blindly
try to call ToString() on the return value from FirstOrDefault(), but
FirstOrDefault() may return null).

Pete

Cralis

unread,
Jul 21, 2010, 4:37:52 PM7/21/10
to
Thanks Pete!
I was 'close' to what you have recommended... but instead of
'abstract', for some stupid reason, I was trying to use 'virtual'.
More brain fade.

Thanks.
I'll try that this evening after work.

Again, thanks fro your time. I'll report with results.

Cralis

unread,
Jul 21, 2010, 5:41:28 PM7/21/10
to
Pete.. progress, but here's another spanner tossed into the works.

I've declared my classes like this now:

public abstract class ConfigurationOptionBase
{
#region Class Properties

public string Name { get; set; }

public string Description { get; set; }

public ConfigOptionValueType ValueType { get; set; }

public ConfigOptionGroup Group { get; set; }

public bool IsAdvanced { get; set; }

public bool IsReadOnly { get; set; }

public float? MaximumValue { get; set; }

public float? MinimumValue { get; set; }

public bool DisplayAsYesNo { get; set; }

public abstract string ValueString { get; }

public abstract string OriginalValue { get; set; }

public abstract bool Modified { get; }

public abstract void SetValue(object Input);

#endregion

}

public class ConfigurationOptionString : ConfigurationOptionBase
{
public string Value { get; set; }

public override string OriginalValue { get; set; }

public override bool Modified
{
get { return OriginalValue != Value; }

}

public override string ValueString
{
get { return Value; }
}

public override void SetValue(object Input)
{
Value = Input.ToString();

}
}

public class ConfigurationOptionFloat : ConfigurationOptionBase


{
public float Value { get; set; }

public override string OriginalValue { get; set; }

public override bool Modified
{
get { return OriginalValue != Value.ToString(); }

}

public override string ValueString
{
get { return Value.ToString(Common.Cuture); }
}

public override void SetValue(object Input)
{
Value = float.Parse(Input.ToString());

}
}

So, for now, I have my base class, with a class for Float and a class
for String. I think I had to make the base class abstract, so that my
sub classes can all have the same fields and methods. The reasoning is
that .. when my application started, I create all the objects (before
I have read them from the device), like place holders. So,l they need
a type, before I know what the type will be. So, I have a whole lot of
calls to this method:

private static ConfigurationOptionBase Add(string name, bool
isAdvanced, ConfigOptionGroup group, bool readOnly, bool
displayAsYesNo)
{
ConfigurationOptionBase ko = new ConfigurationOptionString
{
Name = name,
Group = group,
IsReadOnly = readOnly,
IsAdvanced = isAdvanced,
DisplayAsYesNo =
displayAsYesNo
};
return ko;
}

It sets up an object with the name and some other details... And these
all get added to a List<ConfigurationOptionBase>.

I then connect to the device, and start reading the parameters. I get
the name of the parameter from the device, then find the placeholder
object with that name, and set the values:

So, when going through all the incoming data from the device, I do:

ConfigurationOptionBase tmpOption = GetOption(parameterName, config);

GetOption does this:

private static ConfigurationOptionBase GetOption(string
parameterName, Configuration config)
{
foreach (ConfigurationOptionBase co in
config.ConfigOptions)
{
if (co.Name == parameterName)
{
return co;
}
}

Common.WriteLog("== WARNING: " + parameterName + " found
on OSD, but is not known by me. Adding to Advanced.");

ConfigurationOptionBase newOption = new
ConfigurationOptionString
{
Group =
ConfigOptionGroup.ADVANCED,
Name =
parameterName
};

config.ConfigOptions.Add(newOption);
return newOption;

}
So, it finds the placeholder, and returns that object. If the object
with that name doesn't exist, it logs an issue and creates a new
object with default values. And returns that new object.

Now, once I have the returned object, which is a placeholder... I can
then check the incoming ParameterType field... and based on that, I
now need to change the object type from ConfigurationOptionBase to
either ConfigurationOptionFloat or ConfigurationOptionString.

So, I was hoping to do something like this:

ConfigurationOptionBase tmpOption = GetOption(parameterName, config);

switch(parameterType)
{
case "4": // Float
tmpOption =
(ConfigurationOptionFloat)tmpOption;
break;
case "5": // String
tmpOption =
(ConfigurationOptionString)tmpOption;
break;
default:
option = tmpOption;

}

It's not letting that happen, saying the cast is redundent.. which I
can't see how it can be.

Can you see an issue?

Cralis

unread,
Jul 21, 2010, 5:50:58 PM7/21/10
to
Added to that, I have a problem in that when I create my place holder
objects... I can't create them as Base... because it's abstract, I
think.. So I am creating them as String objects...

And then when I try convert my String object to a Float object, I get
an exception .. can't cast ConfigurationOptionString to
ConfigurationOptionFloat,

Peter Duniho

unread,
Jul 21, 2010, 8:42:09 PM7/21/10
to
Cralis wrote:
> [...]

> Now, once I have the returned object, which is a placeholder... I can
> then check the incoming ParameterType field... and based on that, I
> now need to change the object type from ConfigurationOptionBase to
> either ConfigurationOptionFloat or ConfigurationOptionString.
>
> So, I was hoping to do something like this:
>
> ConfigurationOptionBase tmpOption = GetOption(parameterName, config);
>
> switch(parameterType)
> {
> case "4": // Float
> tmpOption =
> (ConfigurationOptionFloat)tmpOption;
> break;
> case "5": // String
> tmpOption =
> (ConfigurationOptionString)tmpOption;
> break;
> default:
> option = tmpOption;
>
> }
>
> It's not letting that happen, saying the cast is redundent.. which I
> can't see how it can be.
>
> Can you see an issue?

A cast cannot change the type of an object (†). It can only change the
type being used as the context for an object. So, you can't start with
an object of type ConfigurationOptionBase and convert it to (for
example) ConfigurationOptionFloat simply by casting it to that.

In the above code example, the issue that the compiler is complaining
about is that even if the object were of the correct type, downcasting
to ConfigurationOptionFloat only to then store that reference back into
a variable types as ConfigurationOptionBase accomplishes nothing at all,
hence the "redundant". But (and this is why that error exists) the
redundancy is really a sign of a larger issue: the cast doesn't do what
you seem to think it does.

Frankly, if I were you I would look for a different design. The idea
that you would start with a list of objects before you know the type and
data of those objects seems very suspect to me.

But, if you insist on following that design, you have two options that
would work:

• When you go through and want to convert the objects to the correct
type and value, create _new_ instances of the appropriate
ConfigurationOptionsBase sub-classes and replace each of the placeholder
instances with the equivalent correct sub-class instance

• Forget about having strongly typed classes altogether. Just store
"object" and cast as necessary based on the indicated type when you need
to use the data.

A third option would be:

• Split the type design into two, with a placeholder type that
contains the information known before initialization, and a data-holding
type that contains the actual data.

This third option is very similar to simply forgetting about strong
typing, except that by providing your own data-holding class instead of
"object", you _might_ have the opportunity to include features in that
class that help your program work better (but without knowing all of the
details of the program — details I probably don't really even have time
to understand at the moment — I can't really say whether that would work
out in your case or not).

Pete

(†) Actually, there is one situation in which you can use casting to
actually convert from one type to another: when an explicit conversion
operator has been declared.
http://msdn.microsoft.com/en-us/library/09479473.aspx

It's possible you would find your code more readable implementing it
that way, but note that you still will have to replace the original
object instance with your new object instance created by the explicit
conversion.

Peter Duniho

unread,
Jul 21, 2010, 8:43:35 PM7/21/10
to

That's correct. But even if you could create the objects as
ConfigurationOptionBase you would still have the same problem; you can't
convert an instance of ConfigurationOptionBase to either
ConfigurationOptionString or ConfigurationOptionFloat, not without
actually creating a new instance of the new type you want, copying the
relevant state from the ConfigurationOptionBase instance, and then
replacing that instance with the new sub-class instance.

Pete

Cralis

unread,
Jul 22, 2010, 6:00:34 AM7/22/10
to
Agh! Pete, don't leave me hanging! :)

I'm pretty stuck right now. :(

Cralis

unread,
Jul 22, 2010, 6:07:58 AM7/22/10
to
Sorry - replied in error. Never saw your replies... Google Groups side
uses page!? :) Reading now.
0 new messages