Question about C# 4.0's generics covariance - c#

Having defined this interface:
public interface IInputBoxService<out T> {
bool ShowDialog();
T Result { get; }
}
Why does the following code work:
public class StringInputBoxService : IInputBoxService<string> {
...
}
...
IInputBoxService<object> service = new StringInputBoxService();
and this doesn't?:
public class IntegerInputBoxService : IInputBoxService<int> {
...
}
...
IInputBoxService<object> service = new IntegerInputBoxService();
Does it have anything to do with int being a value type? If yes, how can I circumvent this situation?
Thanks

Yes, it absolutely has to do with int being a value type. Generic variance in C# 4 only works with reference types. This is primarily because references always have the same representation: a reference is just a reference, so the CLR can use the same bits for something it knows is a string reference as for an object reference. The CLR can make sure that the code will be safe, and use native code which only knows about IInputBoxService<object> when passed an IInputBoxService<string> - the value returned from Result will be representationally compatible (if such a term exists!).
With int => object there would have to be boxing etc, so you don't end up with the same code - that basically messes up variance.
EDIT: The C# 4.0 spec says this in section 13.1.3.2:
The purpose of variance annotations is
to provide for more lenient (but still
type safe) conversions to interface
and delegate types. To this end the
definitions of implicit (§6.1) and
explicit conversions (§6.2) make use
of the notion of
variance-convertibility, which is
defined as follows: A type T is variance-convertible to a type
T if T is either an
interface or a delegate type declared
with the variant type parameters T, and for each variant type
parameter Xi one of the following
holds:
Xi is covariant and an
implicit reference or identity
conversion exists from Ai to Bi
Xi
is contravariant and an implicit
reference or identity conversion
exists from Bi to Ai
Xi is invariant
and an identity conversion exists from
Ai to Bi
This doesn't make it terribly obvious, but basically reference conversions only exist between reference types, which leaves only identity conversions (i.e. from a type to itself).
As for workarounds: I think you'd have to create your own wrapper class, basically. This can be as simple as:
public class Wrapper<T>
{
public T Value { get; private set; }
public Wrapper(T value)
{
Value = value;
}
}
It's pretty nasty though :(

Related

Why my class act so weird with implicit converters [duplicate]

I have a generic class that I'm trying to implement implicit type casting for. While it mostly works, it won't work for interface casting. Upon further investigation, I found that there is a compiler error: "User-defined conversion from interface" that applies. While I understand that this should be enforced in some cases, what I'm trying to do does seem like a legitimate case.
Here's an example:
public class Foo<T> where T : IBar
{
private readonly T instance;
public Foo(T instance)
{
this.instance = instance;
}
public T Instance
{
get { return instance; }
}
public static implicit operator Foo<T>(T instance)
{
return new Foo<T>(instance);
}
}
Code to use it:
var concreteReferenceToBar = new ConcreteBar();
IBar intefaceReferenceToBar = concreteReferenceToBar;
Foo<ConcreteBar> concreteFooFromConcreteBar = concreteReferenceToBar;
Foo<IBar> fooFromConcreteBar = concreteReferenceToBar;
Foo<IBar> fooFromInterfaceBar = intefaceReferenceToBar; // doesn't work
Does anyone know a workaround, or can anyone explain in a satisfactory way why I shuouldn't be able to cast interfaceReferenceToBar implicitly to Foo<IBar>, since in my case it is not being converted, but only contained within Foo?
EDIT:
It looks like covariance might offer salvation. Let's hope the C# 4.0 specification allows for implicit casting of interface types using covariance.
The reason you can't do this is because it is specifically forbidden in the C# language specification:
Source: ECMA-334 Section 15.10.4
A class or struct is permitted to
declare a conversion from a source
type S to a target type T provided all
of the following are true:
...
Neither S nor T is object or an interface-type.
and
User-defined conversions are not
allowed to convert from or to
interface-types. In particular, this
restriction ensures that no
user-defined transformations occur
when converting to an interface-type,
and that a conversion to an
interface-type succeeds only if the
object being converted actually
implements the specified
interface-type.

Explicit cast explanation in terms of memory for reference type in C#

In MSDN, "For reference types, an explicit cast is required if you need to convert from a base type to a derived type".
In wiki, "In programming language theory, a reference type is a data type that refers to an object in memory. A pointer type on the other hand refers to a memory address. Reference types can be thought of as pointers that are implicitly dereferenced." which is the case in C.
How to explain the memory storing procedure when considering explicit casting for reference type in C#?
For most cases, there's really not much conceivable difference between a reference variable and a pointer variable. Both point to a location in memory. The type of the reference (or pointer) variable tells the compiller which operations can be performed using it.
Instead of C pointers, which are (primarily) used with basic types (such as int or byte), consider C++ object pointers first. It's really almost the same as in C#:
MyBaseClass* a = new MyBaseclass();
a->BaseMethod(); // Call method using -> operator (dereference and call)
MyBaseClass* b = new MyDerivedClass();
b->DerivedMethod(); // Error: MyBaseClass has no such method
// Proper C++-Style casting.
MyDerivedClass* c = dynamic_cast<MyDerivedClass*>(b);
// Shortcut to the above, does not do the type test.
// MyDerivedClass* c = (MyDerivedClass*)b;
c->DerivedMethod(); // Ok
This translates almost 1:1 to C#, so reference types are (from a programmer point of view) just pointers with a defined type. The only visible difference would be that a direct C-Style cast in C# is equivalent to a try_cast in C++, which will ensure that you can never assign a wrong target instance to a reference variable.
So the differences between a reference type and a pointer to an object are (most of these are implied by the fact that C# is a managed language):
A reference variable can never point to invalid memory (except to NULL).
A reference variable can never point to an object that's not of its type.
When assigning a value to a reference variable, the type is always tested.
A cast on a reference variable needs to check that the target object is of the given type.
The reference objects are stored on a heap, where they can be referenced from the code. The object, as it is on the heap, is of a given type.
From the code, you can create references to it, and those references can be cast to some some other types.
Now, there are couple of cases, which are described in the referenced article. I will use the examples from there to make it easier.
1. Implicit conversions
Implicit conversion takes place, when you don't ask for it specifically in code. Compiler has to know by itself how to do this.
1.1. Value Types
If the type of value that you are trying to cast is of size, that allows you to store it in the size of memory that makes the size of the type you want to cast to, then compiler will let you do that. This is mostly for numeric values, so following the examples from your referenced article:
// Implicit conversion. num long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;
So since int is 'smaller' than long, compiler will let you do this.
1.2. Reference Types
Assuming you have following classes definitions:
class Base {
}
class Derived : Base {
public int IntProperty { get; set; }
public int CalculateSomething ()
{
return IntProperty * 23;
}
}
Then you can safely do conversions like:
Derived d = new Derived();
Base b = d;
This is because object d, which you have created on the heap, is of type Derived, and since it's a derived type from type Base, it is guaranteed to have all members that Base has. So it's safe to convert the reference and use Derived object as Base object. Because Derived IS Base (Derived : Base).
2. Explicit conversions
Let's assume we have another class in our project:
class DerivedLike
{
public int IntProp { get; set; }
public int CalculateSomethingElse()
{
return IntProp * 23;
}
}
If we write
DerivedLike dl = new DerivedLike();
Derived d = dl;
we'll get from our compiler that it cannot implicitly convert type DerivedLike to Derived.
This is, because the two reference types are totally different, so compiler cannot allow you to do that. Those types have different properties and methods.
2.1. Implementing explicit conversion
As long as you cannot convert from Derived class to Base class by yourself, you can write an operator in most other cases.
If one wants to proceed with conversion from DerivedLike to Derived, we must implement in the DerivedLike class, a conversion operator. It's a static operator which tells how to convert one type to another. The conversion operator may be either implicit, or explicit. Explicit will require the developer to cast it explicitly, by providing the Type name in the parenthesis.
The recommendation for choosing between implicit and explicit operators is that if conversion may throw exceptions, it should be explicit, so that conversion is done consciously by the developer.
Let's change our code to meet that requirement:
class DerivedLike
{
public static explicit operator Derived(DerivedLike a)
{
return new Derived() { IntProperty = a.IntProp};
}
public int IntProp { get; set; }
public int CalculateSomethingElse()
{
return IntProp * 23;
}
}
So this will compile fine now:
DerivedLike dl = new DerivedLike();
Derived d = (Derived)dl;
Going back to memory topic, please note, that with such conversion, you will now have two objects on the heap.
One created here:
DerivedLike dl = new DerivedLike();
Second one created here:
Derived d = (Derived)dl;
The object on the heap cannot change it's type.
Hope this clarifies.

Is "where T : class" not enforced in any way at compile time or run time?

In the following code, I pass a struct into a constructor that is expecting a class. Why does this compile and run without error (and produce the desired output)?
class Program
{
static void Main()
{
var entity = new Foo { Id = 3 };
var t = new Test<IEntity>(entity); // why doesn't this fail?
Console.WriteLine(t.Entity.Id.ToString());
Console.ReadKey();
}
}
public class Test<TEntity> where TEntity : class
{
public TEntity Entity { get; set; }
public Test(TEntity entity)
{
Entity = entity;
}
public void ClearEntity()
{
Entity = null;
}
}
public struct Foo : IEntity
{
public int Id { get; set; }
}
public interface IEntity
{
int Id { get; set; }
}
If I change my Main() method so that it includes a call to ClearEntity(), as shown below, it still generates no error. Why?
static void Main()
{
var entity = new Foo { Id = 3 };
var t = new Test<IEntity>(entity);
Console.WriteLine(t.Entity.Id.ToString());
t.ClearEntity(); // why doesn't this fail?
Console.ReadKey();
}
where TEntity : class forces TEntity to be a reference type, but an interface such as IEntity is a reference type.
See here:
http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx
where T : class | The type argument must be a reference type, including any class, interface, delegate, or array type
Regarding your second question, you might think t.ClearEntity() would fail because it's assigning null to a variable whose type is a value type, but that's not the case. The compile-time type of Entity is the reference type IEntity, and the runtime type (after assignment) is the null type. So you never have a variable of type Foo but value null.
from the C# documentation:
where T : class
The type argument must be a reference type, including any class, interface, delegate, or array type. (See note below.)
Because you're passing the struct via an interface, it's still considered a reference type.
Within the .net runtime, every non-nullable value type has an associated reference type (often referred to as a "boxed value type") which derives from System.ValueType. Saying Object Foo = 5; won't actually store an Int32 into Foo; instead it will create a new instance of the reference type associated with Int32 and store a reference to that instance. A class constraint on a generic type specifies that the type in question must be some sort of a reference type, but does not by itself exclude the possibility that the type may be used to pass a reference to a boxed value-type instance. In most contexts outside generic type constraints, interface types are regarded as class types.
It's important to note that not only are boxed value types stored like reference types; they behave like reference types. For example, List<string>.Enumerator is a value type which implements IEnumerator<string>. If one has two variables of type List<string>.Enumerator, copying one to the other will copy the state of the enumeration, such that there will be two separate and independent enumerators which point to the same list. Copying one of those variables to a variable of type IEnumerator<string> will create a new instance of the boxed value type associated with List<string.Enumerator and store in the latter variable a reference to that new object (which will be a third independent enumerator). Copying that variable to another of type IEnumerator<string>, however, will simply store a reference to the existing object (since IEnumerator<string> is a reference type).
The C# language tries to pretend that value types derive from Object, but within the guts of the .net Runtime they really don't. Instead, they're convertible to types which derive from System.ValueType (which in turn derives from Object). The latter types will satisfy a type constraint, even though the former ones will not. Incidentally, despite its name, System.ValueType is actually a class type.
I, likewise, assumed that constraint keyword class meant the same class as the type declaration keyword class, but it doesn't.
As explained in the other answers, the term class here is over-loaded, which seems to me to be a horrible decision for the C# language design. Something like referencetype would have been more helpful.

Structs, Interfaces and Boxing [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it safe for structs to implement interfaces?
Take this code:
interface ISomeInterface
{
public int SomeProperty { get; }
}
struct SomeStruct : ISomeInterface
{
int someValue;
public int SomeProperty { get { return someValue; } }
public SomeStruct(int value)
{
someValue = value;
}
}
and then I do this somewhere:
ISomeInterface someVariable = new SomeStruct(2);
is the SomeStruct boxed in this case?
Jon's point is true, but as a side note there is one slight exception to the rule; generics. If you have where T : ISomeInterface, then this is constrained, and uses a special opcode. This means the interface can be used without boxing. For example:
public static void Foo<T>(T obj) where T : ISomeInterface {
obj.Bar(); // Bar defined on ISomeInterface
}
This does not involve boxing, even for value-type T. However, if (in the same Foo) you do:
ISomeInterface asInterface = obj;
asInterface.Bar();
then that boxes as before. The constrained only applies directly to T.
Yes, it is. Basically whenever you need a reference and you've only got a value type value, the value is boxed.
Here, ISomeInterface is an interface, which is a reference type. Therefore the value of someVariable is always a reference, so the newly created struct value has to be boxed.
I'm adding this to hopefully shed a little more light on the answers offered by Jon and Marc.
Consider this non-generic method:
public static void SetToNull(ref ISomeInterface obj) {
obj = null;
}
Hmm... setting a ref parameter to null. That's only possibly for a reference type, correct? (Well, or for a Nullable<T>; but let's ignore that case to keep things simple.) So the fact that this method compiles tells us that a variable declared to be of some interface type must be treated as a reference type.
The key phrase here is "declared as": consider this attempt to call the above method:
var x = new SomeStruct();
// This line does not compile:
// "Cannot convert from ref SomeStruct to ref ISomeInterface" --
// since x is declared to be of type SomeStruct, it cannot be passed
// to a method that wants a parameter of type ref ISomeInterface.
SetToNull(ref x);
Granted, the reason you can't pass x in the above code to SetToNull is that x would need to be declared as an ISomeInterface for you to be able to pass ref x -- and not because the compiler magically knows that SetToNull includes the line obj = null. But in a way that just reinforces my point: the obj = null line is legal precisely because it would be illegal to pass a variable not declared as an ISomeInterface to the method.
In other words, if a variable is declared as an ISomeInterface, it can be set to null, pure and simple. And that's because interfaces are reference types -- hence, declaring an object as an interface and assigning it to a value type object boxes that value.
Now, on the other hand, consider this hypothetical generic method:
// This method does not compile:
// "Cannot convert null to type parameter 'T' because it could be
// a non-nullable value type. Consider using 'default(T)' instead." --
// since this method could take a variable declared as, e.g., a SomeStruct,
// the compiler cannot assume a null assignment is legal.
public static void SetToNull<T>(ref T obj) where T : ISomeInterface {
obj = null;
}
The MSDN documentation tells us that structs are value, not reference types. They are boxed when converting to/from a variable of type object. But the central question here is: what about a variable of an interface type? Since the interface can also be implemented by a class, then this must be tantamount to converting from a value to a reference type, as Jon Skeet already said, therefore yes boxing would occur. More discussion on an msdn blog.

implicit operator using interfaces

I have a generic class that I'm trying to implement implicit type casting for. While it mostly works, it won't work for interface casting. Upon further investigation, I found that there is a compiler error: "User-defined conversion from interface" that applies. While I understand that this should be enforced in some cases, what I'm trying to do does seem like a legitimate case.
Here's an example:
public class Foo<T> where T : IBar
{
private readonly T instance;
public Foo(T instance)
{
this.instance = instance;
}
public T Instance
{
get { return instance; }
}
public static implicit operator Foo<T>(T instance)
{
return new Foo<T>(instance);
}
}
Code to use it:
var concreteReferenceToBar = new ConcreteBar();
IBar intefaceReferenceToBar = concreteReferenceToBar;
Foo<ConcreteBar> concreteFooFromConcreteBar = concreteReferenceToBar;
Foo<IBar> fooFromConcreteBar = concreteReferenceToBar;
Foo<IBar> fooFromInterfaceBar = intefaceReferenceToBar; // doesn't work
Does anyone know a workaround, or can anyone explain in a satisfactory way why I shuouldn't be able to cast interfaceReferenceToBar implicitly to Foo<IBar>, since in my case it is not being converted, but only contained within Foo?
EDIT:
It looks like covariance might offer salvation. Let's hope the C# 4.0 specification allows for implicit casting of interface types using covariance.
The reason you can't do this is because it is specifically forbidden in the C# language specification:
Source: ECMA-334 Section 15.10.4
A class or struct is permitted to
declare a conversion from a source
type S to a target type T provided all
of the following are true:
...
Neither S nor T is object or an interface-type.
and
User-defined conversions are not
allowed to convert from or to
interface-types. In particular, this
restriction ensures that no
user-defined transformations occur
when converting to an interface-type,
and that a conversion to an
interface-type succeeds only if the
object being converted actually
implements the specified
interface-type.

Categories

Resources