Object with field that can be any type

C

Cralis

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";
 
C

Cralis

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?
 
M

Mark

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

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.
 
M

Mark

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.
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.
 
M

Mark

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


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



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

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.
 
C

Cralis

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?
 
C

Cralis

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).
 
M

Mark

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();
}
}
 
M

Mark

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

Okie dokie
 
C

Cralis

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.
 
C

Cralis

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.
 
C

Cralis

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?
 
C

Cralis

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,
 
C

Cralis

Sorry - replied in error. Never saw your replies... Google Groups side
uses page!? :) Reading now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top