views:

111

answers:

5

I have a C# wraper class with a series of methods accepting various data types:

public class MyClass
{
    public void ProcessString(string Value) { // implementation }
    public void ProcessInt(int? Value) { // implementation }\
    public void ProcessOther(MyClass Value) { // implementation }
}

I now want to add a generic ProcessObject() method to avoid the need to explicitly cast an object before calling a relevant process method:

public void ProcessObject(object Value)
{
    if (CanCastToString(Value)
    {
        ProcessString((string)Value);
    }
    else if (CanCastToInt(Value))
    {
        ProcessInt((int?)Value);
    }
    // etc...
}

The trouble is that I don't know what my CanCastToInt methods should be - I need these methods to be able to be robust and deal with things like nullable types and other user defined casts.

How can I do this? All I want to know is if a given object can be cast to a given type, i.e. whether or not:

(SomeType)Value

Will work.

+1  A: 

you need is operator. CanCastToString(x) -> x is string.

Andrey
Doesn't work - consider the case when `x` is a `Nullable<int>`, and then `x is int` returns false, but `(int)x` works fine.
Kragen
@Kragen: Are you *sure* about that? Suppose the expression is of compile-time type Nullable<int>. Then you don't *need* the "is" operator because you already *know* the exact type of the object. Suppose the expression is not of compile-time type Nullable<int>. What possible type could it be? *It has to be something boxed*. And there is no such thing as a boxed nullable int! A nullable int either boxes to a null reference or to a boxed int. (A puzzle for you: my analysis is not entirely correct. What case did I miss?)
Eric Lippert
+4  A: 

There are two main ways this is usually done:

if (Value is SomeType)
{
    // Do something with a cast
}

or

var v = Value as SomeType;
if (v != null)
{
    // Value was successfully cast as SomeType
}

When working with structs or intrinsic types, make them nullable:

var v = Value as int?;
if (v != null)
{
    ProcessInt(v.Value);
}
Toby
A: 
    public void QuickTest()
    {
        object stringObj = "string";
        object nullableInt1 = (int?)null;
        object nullableInt2 = (int?)1;
        object decimalObj = 1.5m;

        ProcessObject(stringObj);
        ProcessObject(nullableInt1);
        ProcessObject(nullableInt2);
        ProcessObject(decimalObj);
    }

    public void ProcessObject(object value)
    {
        if (value == null)
        {
            Debug.WriteLine("null");
            return;
        }


        if (value is string)
        {
            Debug.WriteLine((string)value);
            return;
        }

        string stringValue = value.ToString();

        int intTemp;
        if (int.TryParse(stringValue, out intTemp))
        {
            Debug.WriteLine(intTemp);
            return;
        }

        decimal decimalTemp;
        if (decimal.TryParse(stringValue, out decimalTemp))
        {
            Debug.WriteLine(decimalTemp);
            return;
        }
        // etc...
    }
Bill
+2  A: 

Why not expose your processing API directly, with overloads for various parameters?

public class MyClass
{
    public void Process(string Value) { // implementation }
    public void Process(int Value) { // implementation }\
    public void Process(MyClass Value) { // implementation }
    public void Process(object Value) { // catch all method. Handle unknown entities, e.g. call ToString() }
}

EDIT With some generics magic you can have a single interface method, a bunch of helper methods that do the work and one catch-all method where you handle corner cases.

public class MyClass
{
    void DoProcess(string Value) { // implementation }
    void DoProcess(int Value) { // implementation }\
    void DoProcess(MyClass Value) { // implementation }
    void DoProcess(object Value) { 
        // catch all method. Handle unknown entities, e.g. call ToString()
    }
    public void Process<T>(T value) {
       //this method will call the right overload of DoProcess depending on the compile time type of value. If there isn't a match, it goes to DoProcess(object)
       DoProcess(value);
    }
}

This way you avoid boxing for fundamental types and have slightly better type safety.

For your catch-all method you can try using Type.IsAssignableFrom method. For example:

if (typeof(short).IsAssignableFrom(Value)
    DoProcess((short)Value);
if (typeof(byte).IsAssignableFrom(Value)
    DoProcess((byte)Value);

I do recommend that you read Eric Lippert's essay about representation casts. Hopefully, after doing that, you will come to realisation that it might just be easier to have an overload for each supported type. Also, you might realise that dealing with unboxing value types could be a road to hell.

Igor Zevaka
I have already, but I want also want to expose a generic method that uses objects as it makes things easier elsewhere.
Kragen
+1  A: 

If (unlike OP?) you don't know the type involved until runtime you may try to employ some variation of this:

http://codegoeshere.blogspot.com/2007/05/dynamic-cast-in-c.html

Tim Lovell-Smith