Question

Back to the basics...

For reference types, one can do this:

        SomeType someObject = firstObject as SomeType;
        if (someObject == null)
        {
            // Handle the situation gracefully
        }
        else
        {
            // Do stuff
        }

For value types, my understanding is that we have implicit conversions (no data loss), explicit conversions (needed if there's a risk of data loss), the Convert class (a "conversion wrapper" I think) and also type-specific conversions (e.g. double x = Double.Parse("2");), but I haven't found anything similar to the as operator above.

So, my question is: does the framework provide with some method/operator/technique to do something along these lines:

        if (!Convert.CanConvert(someValue, someValueType))
        {
            // Beware! Data loss can occur
        }
        else
        {
            // No data loss here
        }

If not, can anyone out there suggest a solid approach to build one such CanConvert method?

Thanks a lot!

EDIT(1): The user-case/problem is as follows: Given a something passed by the code's consumer (my other self, but that's irrelevant), (1) Check that something is a number (easy enough) and (2) Place something in the "smallest" numeric type where it fits without incurring in data loss.

Some background: the nature of what I'm trying to do is more mathematical than technical: I'm trying to see if/how I can fit existing numeric types into some sort of an algebraic hierarchy of the form Monoid=>Group=>Ring=>Field (or a simplified version thereof). While working on this, and not very sure how, "one thing led to another" and I found myself having to deal with type conversions...

Was it helpful?

Solution

How about the TryParse method on the various value types?

int x;

if (int.TryParse(someType.ToString(), out x))
    return x;

OTHER TIPS

Henk is pretty much on the money. I'd like to add something to his answer, if I would:

Value-type conversion in the .NET Framework works using the IConvertible interface. The Convert class makes use of this for almost all of its methods. This is very different from implicit/explicit conversion operators in C#, which are merely another form of syntactic sugar.

If you write this:

public struct Duck
{
    public static implicit operator Goose(Duck d)
    {
        ...
    }
}

The .NET Framework itself has no idea that this exists. It is emitted as an op_implicit and it's up to the compiled language to figure out how to use it. Not every MSIL language actually supports these. So this code works:

Goose g1 = duck;

This code doesn't:

Goose g1 = (Goose)Convert.ChangeType(duck, typeof(Goose));

In order to implement a CanConvert method that is aware of implicit/explicit conversion operators, you would actually have to use Reflection to check for the individual op_ methods, and I'd have to recommend against doing that - I can see little use for it in practice.

Take a look at Convert.ChangeType. You could hijack that to meet your purposes, though it would be slow due to exception throwing and duplicate conversion.

the "as" keyword is basically a safe downcast. Since all value types are sealed, they cannot be inherited from.

So your code would be:

if (firstObject is MyValueType)
{
   MyValueType obj = (MyValueType) firstObject;
}
else
{
}

I think you are misunderstanding the point of the as operator. The as operator is roughly equivalent to the following code:

if (firstObject is SomeType)
  return (SomeType)firstObject;
else
  return null;

So as is more of an inheritance check. (Such as List implements IList)

Value types do not support inheritance, and for good reason. Double and Int64 both store the number 1 in completely different manners.

Basically what you want is a method that will determine for you whether a number conversion is loseless or not. Well I counter with "Why?". While there are quite a few formats supported by the CLR, the conversion rules are usually pretty simple. For example Int32 -> Double is lossless, and any conversion from a "smaller" to a "larger" is lossless, such as SByte -> Int64.

Another question is, what would a false in your example signify? I would say very little, for example:

Convert.CanConvert(123456789.12345F, typeof(Byte))

Of what use is the false result? You imply it is for cases like Int32 -> Single, where some data would be lost, but in this case a ton of data is being lost, as the "closest" Byte representation is 255.

It is because of these two issues that there is no such method.

The as operator is based on inheritance, and value types don't inherit. You could probably write a CanConvert() but it would have to work with Boxed valuetypes, and you normally want to avoid boxing.

So, Possible: Yes, Desirable: No.

Maybe you can add a Use-Case scenario where you want to use this and then we can recommend alternatives.

Re: Edit(1)

I hope you are aware that the system of numerical types is mostly historical baggage and does not follow very logical rules. There is for instance no such thing as a short calculation, they are always converted to int before doing anything.

But maybe you can define that behaviour in terms of Ring and Field, that Algebra has been a "long time passing" for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top