6

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

d..
  • 1,063
  • 1
  • 10
  • 18
  • Re: your edit - I actually do something like this as part of an inline compression algorithm. My method? Start with a `long`, compare it against `byte.MaxValue`, then `short.MaxValue`, and then `int.MaxValue`, and cast it to the smallest one that fits! – Aaronaught Jan 23 '10 at 20:25
  • I'm trying something very similar to this following the suggestion by Rob below. Same idea: try conversions following a pre-defined order (I consider anything unsigned "smaller" than anything signed for mathematical reasons, even if memory-wise this is not true). BTW: do you have any web/blog where I could check your algorithm? – d.. Jan 23 '10 at 20:50

6 Answers6

3

How about the TryParse method on the various value types?

int x;

if (int.TryParse(someType.ToString(), out x))
    return x;
Jacob
  • 77,566
  • 24
  • 149
  • 228
Rob Packwood
  • 3,698
  • 4
  • 32
  • 48
2

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.

Aaronaught
  • 120,909
  • 25
  • 266
  • 342
1

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.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Oh yes, I think anyone who has ever worked with numbers in computers is aware that they don't follow very logical rules. So here I am building my own. In privacy of my home, of course... :-) – d.. Jan 23 '10 at 19:45
1

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.

dkackman
  • 15,179
  • 13
  • 69
  • 123
  • Thanks - I checked it before posting and I agree, it doesn't look great for my purpose. – d.. Jan 23 '10 at 19:37
1

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
{
}
tster
  • 17,883
  • 5
  • 53
  • 72
1

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.

Guvante
  • 18,775
  • 1
  • 33
  • 64