21

I have defined implicit string conversion from/to a certain type in C# (dummy code):

public class MyType
{
    public string Value { get; set; }

    public static implicit operator MyType(string fromString)
    {
        return new MyType { Value = fromString };
    }

    public static implicit operator string(MyType myType)
    {
        return myType.Value;
    }
}

Somewhere in external library code, an instance of MyType is passed to a method, as an object parameter. Part of that method looks like something along these lines:

private void Foo(object value)
{
    // ... code omitted
    var bar = value as string // note that value is an instance of MyType at runtime
    if(bar != null) // false, cast fails
    {
       // ... code omitted
    }
}

Why does the cast not use the implicit converter? I thought the whole point of these was to make casting and transparent usage possible?

Would this work if MyType had an explicit converter instead? If so, (how) can I have both?

By the way, the cast definitely works if the type is known at compile-time. Is this because operators are static? Is there something like non-static conversion operators?

P.S. I'm actually most interested in the differences between compile-time behaviour and runtime behaviour, so I've a follow-up question: Why are implicit type conversion operators not dynamically usable at runtime in C#?

Community
  • 1
  • 1
MarioDS
  • 12,895
  • 15
  • 65
  • 121
  • 3
    As an aside, I've never heard the `as` operator referred to as a "soft cast" before. – Jon Skeet Feb 19 '16 at 14:52
  • @JonSkeet that genuinely surprises me, maybe not an official term but I've definitely seen it lots of times. – MarioDS Feb 19 '16 at 14:54
  • A search for "soft cast" and C# gets me 636 results, which is a *tiny* number in my view. I would definitely avoid it in the future - it's certainly *not* part of the C# specification terminology. – Jon Skeet Feb 19 '16 at 14:55
  • 1
    @JonSkeet is there a similarly succinct (but more correct) equivalent term? – Richard Ev Feb 19 '16 at 14:58
  • @RichardEverett: It's "the `as` operator". That's all. – Jon Skeet Feb 19 '16 at 14:59
  • @JonSkeet I'll keep that in the back of my head should I ever need it in more official or public communication. My teammates understand me when I use it however, which is most important I think. – MarioDS Feb 19 '16 at 15:02
  • 2
    @MDeSchaepmeester: But in that case you're just reinforcing the use of non-standard terminology within your team. If you use the standard terminology I suspect they'll *also* understand you - but none of you will have to change how you talk when discussing things externally. – Jon Skeet Feb 19 '16 at 15:07
  • Why are you using "as"? You defined implicit operators, so why not just do: string bar = value; Or you could define your method as: public void Foo(string value). If you want it to be more transparent, then just use an explicit conversion. – Joseph M. Shunia Feb 19 '16 at 15:13
  • @returnsvoid that is library code, as mentioned in the question, I have no control over it. – MarioDS Feb 19 '16 at 15:13
  • Ah, I missed that. My mistake. – Joseph M. Shunia Feb 19 '16 at 15:14
  • I've edited the title again, as you'd changed it to "explicit cast". Your code doesn't use an explicit cast - it uses the `as` operator. If you'd used `string bar = (string) value`; that would have failed for a *different* reason. – Jon Skeet Feb 19 '16 at 15:36
  • @JonSkeet I actually wanted to know why it would not work either way. The original wording of my question was off, since I also tested it with an explicit cast but the difference was that the type was known at compile-time (silly oversight, I know). I blamed the `as` operator, while I should have been blaming the runtime behaviour. – MarioDS Feb 19 '16 at 15:42
  • @MDeSchaepneester: well it's still a good idea for the title to match the body of the question :) I suggest you edit the text in the body to match the code too. If you wanted to ask about an actual cast, it would have been worth doing that to start with. As it is, if you want to cover casts as well, I suggest you do that in a new question. – Jon Skeet Feb 19 '16 at 15:46
  • @JonSkeet You're right, hence a follow-up question: http://stackoverflow.com/q/35509502/1313143 – MarioDS Feb 19 '16 at 15:59
  • Possible duplicate of [C# Implicit Conversion Operator and is/as operator](http://stackoverflow.com/questions/18390664/c-sharp-implicit-conversion-operator-and-is-as-operator) – chue x Feb 19 '16 at 20:49

4 Answers4

20

Why does the soft cast not use the implicit converter?

Well, that's the way the language is specified, basically. From the C# 5 specification section 7.10.11:

If the compile-time type of E is not dynamic, the operation E as T produces the same result as

E is T ? (T)(E) : (T)null

except that E is only evaluated once.

[...]

Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That's clear enough, but would you know of any workarounds? What if I really wanted to have a type that behaves almost completely like a string (or an int, or anything else for that matter)? – MarioDS Feb 19 '16 at 14:56
  • 2
    @MDeSchaepmeester: I would just give up on that as an aim, to be honest. There are always going to be problems when trying to make one type look transparently like another. I would backtrack and look at other designs instead. – Jon Skeet Feb 19 '16 at 14:57
  • Fair enough, but had it not been for this one limitation everything would have worked out nicely though. Thanks anyway, if you don't know a workaround then I'm certain no one else does :) – MarioDS Feb 19 '16 at 15:00
10

as keyword doesn't considers the user defined operators. You need to use a cast operator instead. Related article from Eric Lippert

In your case both explicit and implicit operators can't help you as you're trying to cast from object to string not from MyType to string. For user defined conversion operators to work, compile time type of the instance to be of type MyType instead of object. Because there is no conversion exist from object to string but from MyType to string.

Yennefer
  • 5,704
  • 7
  • 31
  • 44
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
9

The C# language Specification explicitly mentions this in the documentation for as:

Note that some conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.

So you have to cast it.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
2

Imagine that an implicit conversion operator would have to get called. In this case, any call

var castObj = rawObj as SomeType;

would require the .NET runtime to use reflection in order to determine whether the "rawObj" object has a conversion operator. Obviously, this would be much more computationally expensive than just to check if the object is of type SomeType or its subtype. Better to have a fast and predictable operator than a more versatile, but much slower one.

IMil
  • 1,391
  • 13
  • 17