6

Possible Duplicate:
Why can't I use interface with explicit operator?

When I do this:

public struct Effect
{
    public IEffect IEffect { get; private set; }

    public Effect ( IEffect effect )
    {
        this.IEffect = effect;
    }

    public static implicit operator IEffect ( Effect effect )
    {
        return effect.IEffect;
    }

    public static explicit operator Effect ( IEffect effect )
    {
        return new Effect ( effect );
    }
}

I get a compiler error like this:

'ImageEditor.Effect.implicit operator ImageEditor.IEffect(ImageEditor.Effect)': user-defined conversions to or from an interface are not allowed.

Why are they not allowed? Is this not a good practice?

Community
  • 1
  • 1
Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • Possible duplicate of: http://stackoverflow.com/questions/2433204/why-cant-i-use-interface-with-explicit-operator – Jeff Yates Jan 31 '11 at 18:33

3 Answers3

7

This is detailed in section 10.10.3 of the C# language spec.

The summary reason of why though is ...

  • Conversion operators should not replace built-in conversions. Allowing this just leads to extremely confusing behavior
  • In general it's not possible to determine if an implicit conversion to an interface is replacing a built-in conversion and hence it's disallowed
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Thanks Jared, in your second reason, by "not possible" you mean by the compiler or the user to determine? I assume it's the user. – Joan Venge Jan 31 '11 at 18:35
  • The predominant reason is that if an object can be converted to IOneInterface and ITwoInterface, then the reference of object via IOneInterface should be castable to ITwoInterface. Overriding operators can break this. (at least that was my understanding) – Jeff Yates Jan 31 '11 at 18:36
  • 1
    @Joan not possible refers to the ability of the compiler to make this determination. Note: it's limited to the general case as there are specific cases (`struct` and `sealed` classes) where the compiler can make this determination. But the C# team decided against this (as to why I can only speculate but my guess is consistency) – JaredPar Jan 31 '11 at 18:37
  • Thanks Jeff, so you mean if you have List that's casted to IEnumerable, then that cast can be directly casted to IList without using the List instance? – Joan Venge Jan 31 '11 at 18:38
  • I guess my logic was "why should the user care?" like if something is later be made castable to an interface or is overriding the explicit casting, why it this any more issue than doing this between types? Like if IEffect was another class/struct, then wouldn't it be just as confusing? (because Effect doesn't drive from IEffect) – Joan Venge Jan 31 '11 at 18:42
  • @Joan Venge: If class "foo" is unsealed, there is no way the compiler can know whether a reference to a "foo" object will also inherently be a reference to an IBar, since it's entirely possible that a derived class foofoo:foo will implement IBar. – supercat Feb 01 '11 at 15:51
  • @JaredPar: I do wish one were allowed to override some existing conversion rules, especially with conversion from a struct to Object. Sometimes it's helpful to have a struct which is supposed to be semantically equivalent to some other class or struct, and features a widening cast to it. The abstraction can work well, but leaks if the struct gets boxed. If one could tell the compiler to perform a widening cast before boxing, then things like Object.Equals would work as they should. – supercat Feb 01 '11 at 15:56
1

The main reason is that an object that implements an interface is always implicitly convertible to its base class, and is always explicitly convertible from its base class to itself. It's redundant and confusing to override this behavior, and you can't override all necessary behavior to make it work properly, and so it's disallowed. In your case, you're overriding some but not all inheritance behavior. For example, best practice when explicitly casting is:

IEffect anIEffectInstance = GetEffectAsInterface();

if(anIEffectInstance is Effect) //<--you cannot override this behavior to return true,
   var interfaceAscConcrete = (Effect)anIEffectInstance; //<-- so this overridden code would never execute
KeithS
  • 70,210
  • 21
  • 112
  • 164
0

Sounds like a question for Jon Skeet or the like, but I'll take a shot at it anyway.

The implicit operator you have described would largely just be unnecessary. If Effect already implements IEffect, you can use an Effect anywhere you need an object implementing IEffect without bothering with a user-defined conversion.

The explicit operator issue may be a little more philosophical. My understanding is that the point of the implicit and explicit conversions is to convert an object of one type to an object of another type whose relationship is not already obvious to the compiler for some reason. An interface is not, however, an object. One cannot instantiate an interface directly; rather, the interface needs to be implemented by some class. When you use either the implicit or explicit conversions, the resulting object is not associated by type to the prior object. That means that the object resulting from the conversion needs to be able to stand independently and have an actual object type, which an interface by itself does not.

Perhaps more directly: What would be the concrete type of the result of the implicit conversion? The compiler has no way of knowing, so it cannot instantiate the object.

If you really need to do something like this, you would want to create an abstract base class that implements the interface. You should then be able to "convert" to and from the abstract base class, which does have an object type.

Andrew
  • 14,325
  • 4
  • 43
  • 64
  • Thanks but Effect doesn't implement IEffect. – Joan Venge Jan 31 '11 at 18:44
  • @Joan Venge You're welcome, but shouldn't Effect implement IEffect? Would what you are attempting to accomplish be served by the state pattern? (http://en.wikipedia.org/wiki/State_pattern) In a nutshell, you would implement IEffect with Effect and use the methods and properties of the stored IEffect to implement IEffect in the Effect class. – Andrew Jan 31 '11 at 18:50
  • Thanks, never heard the state pattern, but this IEffect is a wrapper to an unmanaged API. So I am using composition, not inheritance because it has many elements I don't want to implement and expose to the users of my API. – Joan Venge Jan 31 '11 at 18:56