Explicit implementation on value type leads to rather counter intuitivebehavior...

  • Thread starter Mathieu Cartoixa
  • Start date
M

Mathieu Cartoixa

Hi,

I have been annoyed in one of my recent projects with a problem related
to the explicit implementation of an interface on a value type. I will
take an example to show the problem.

Say we have this simple interface :
interface IInitializable
{
void Init();
}

Let us implement it explicitly in a value type :
struct Struct:
IInitializable
{
public bool Initialized;

void IInitializable.Init()
{
Initialized=true;
}
}

Now if you create a new Struct :
Struct s=new Struct();

You can check that s.Initialized is false. Try to call the Init method
(you have to cast the instance to IInitializable due to the explicit
implementation) :
((IInitializable)s).Init();

Intuitively, you would expect s.Initialized to be true, but in fact it
is still false !
This is explainable, as I figure that there must be some boxing
occuring during the cast, but I found this quite disturbing... I don't
remember having read anything about boxing in casts, and I find this
"feature" quite dangerous. What do you think ?

Mathieu

PS : Here is my complete sample code

using System;

namespace TestValueType
{
interface IInitializable
{
void Init();
}

struct Struct:
IInitializable
{
public bool Initialized;

void IInitializable.Init()
{
Initialized=true;
Console.Out.WriteLine("Struct.Init()");
}
}

class Class:
IInitializable
{
public bool Initialized;

void IInitializable.Init()
{
Initialized=true;
Console.Out.WriteLine("Class.Init()");
}

[STAThread]
static void Main(string[] args)
{
Class c=new Class();
Console.Out.WriteLine("Class.Initialized={0}", c.Initialized);
((IInitializable)c).Init();
Console.Out.WriteLine("Class.Initialized={0}", c.Initialized);
Console.Out.WriteLine();

Struct s=new Struct();
Console.Out.WriteLine("Struct.Initialized={0}", s.Initialized);
((IInitializable)s).Init();
Console.Out.WriteLine("Struct.Initialized={0}", s.Initialized);
Console.Out.WriteLine();

Console.ReadLine();
}
}
}
 
M

Marc Gravell

Agree boxing can be a headache... personally that's partly why I only
generally use structs to define immutable entities... "keep it simple" and
all that...

IIRC, even in 2.0 /standard/ interface casting does involve boxing, however,
I understand (not 100% sure) that an interface contraint on a generic method
does /not/ box... a bit tricky to prove without looking at the IL, however
(since you'd need to use ref, and its unclear if it is simply unboxing
afterwards). I don't /think/ it boxes, though... unless (within the generic
method) you assign it to an interface of the same type as it already
supports!

Marc
 
J

Jon Skeet [C# MVP]

Mathieu Cartoixa wrote:

This is explainable, as I figure that there must be some boxing
occuring during the cast, but I found this quite disturbing... I don't
remember having read anything about boxing in casts, and I find this
"feature" quite dangerous. What do you think ?

Boxing is always involved when you cast a value type to object,
ValueType or an interface type.
From 13.1.5 (ECMA spec):

<quote>
A boxing conversion permits any value-type to be implicitly converted
to the type object or to any interface-type implemented by the
value-type. Boxing a value of a value-type consists of allocating an
object instance and copying the value-type value into that instance.
</quote>

As Marc said, this suggests an inappropriate use of structs.

Jon
 
M

Marc Gravell

For ref, I've just looked at some IL, and it appears to bear this out;
cast to interface = box
generic constraint = not boxed

This only really makes a difference in terms of avoiding the performance
implications of boxing / unboxing - you've still got the headache of
value-type semantics - i.e. the object being cloned as it passes between
different stacks... yup, I'll definitely stick to immutables ;-p

Marc
 
M

Mathieu Cartoixa

Jon Skeet [C# MVP] a écrit :
<snip>

From 13.1.5 (ECMA spec):
<quote>
A boxing conversion permits any value-type to be implicitly converted
to the type object or to any interface-type implemented by the
value-type. Boxing a value of a value-type consists of allocating an
object instance and copying the value-type value into that instance.
</quote>

As Marc said, this suggests an inappropriate use of structs.

Jon

Well, you know how it goes : I started with simple structures (similar
to SqlInt16, SqlInt32...), and one day I realized that they would have
to be "internally mutable", i.e. mutable only inside the library I was
building. I (wrongly) figured that explicit implementation of an
interface would do the trick.
As for the C# Reference (MSDN), it just states that "Structs can
implement an interface but they cannot inherit from another struct." and
that "A struct can implement interfaces."...

Anyway, thanks for your lights.

Mathieu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top