I have a bit of a strange issue here. I have a project constraint where a value of a Property needs to either be a number (int
, double
, long
, etc are all acceptable), a string
, or a datetime
. The reason that the Value parameter needs to be of one these three (err..well if you count all of the possible numeric value Types allowed it's a bit more) Types is because depending on the type the underlying value will need to be converted to special formats for serialization to a REST API. To simplify things here is a basic idea of the class as a POCO:
class Foo
{
public string Name {get;set;}
public Guid Id {get; set;}
public UNKNOWN Value {get;set;}
}
I thought about using generics for this, with a where T : struct
constraint, but this still leaves too many types that can theoretically be set that are actually invalid Types. Sure I can perform type checking and throw exceptions during construction/setting of the Value parameter, but this doesn't feel like "clean" code.
I took a look at this question How do you work with a variable that can be of multiple types? , but it didn't really help since it was more of an issue dealing with inheritance. However, using multiple nullable private fields and returning a single Property based on which one was populated is a possibility, but again I feel there has to be a better way.
The other possibility I was thinking of was to use the dynamic
type and and perform some reflection magic to check the underlying type (and perform conversions & formatting/throw exceptions). I'm a bit scared that this will really hurt performance though.
Are there any best practices for this situation? If not, are there any better ways to handle this from what I've mentioned?
You could use a dedicated class as a "multiple type variable".
At instantiation time you can pass an int
, double
, long
, etc. and when you need to get the stored value out you can use a separate call.
public class Foo
{
public class Value
{
object _value;
public Value(int value) { _value = value; }
public Value(double value) { _value = value; }
public Value(long value) { _value = value; }
// etc
public object GetValue() { return _value; }
}
public void TestCall()
{
Value myValue = new Value(123);
Debug.WriteLine(myValue.GetValue());
}
}
EDIT Eric Lippert taught me this type of dispatch in one of his epic stackoverflow answers, and I'm searching for it at the moment. I will update this answer with a link if/when I track it down (the man has answered quite a few questions). Also, OP, you asked about performance, take a gander at this info also from Lippert: How does having a dynamic variable affect performance?
I would use a mix of dynamic with special case handling, and a generic type catch all for undefined (not yet implemented) types.
class Foo
{
public dynamic Value { get; set; }
}
class FooHandler
{
public void Serialize(Foo foo)
{
SerializeField(foo.Value);
}
void SerializeField(int field)
{
Console.WriteLine("handle int");
}
void SerializeField<T>(T field)
{
throw new NotImplementedException("Serialization not implemented for type: " + typeof(T));
}
}
class Program
{
[STAThread]
static void Main(string[] args)
{
Foo f = new Foo();
f.Value = 1;
FooHandler handler = new FooHandler();
handler.Serialize(f);
Console.ReadKey();
}
}
And then add types at your leisure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With