public interface IVector<TScalar> {
void Add(ref IVector<TScalar> addend);
}
public struct Vector3f : IVector<float> {
public void Add(ref Vector3f addend);
}
Compiler answer:
"Vector3f does not implement interface member IVector<float>.Add(ref IVector<float>)"
But you can do this:
public interface IVector<T, TScalar>
where T : IVector<T, TScalar>
{
void Add(ref T addend);
}
public struct Vector3f : IVector<Vector3f, float>
{
public void Add(ref Vector3f addend)
{
}
}
However, this means you've got mutable structs, which you shouldn't. To have immutable ones, you'd need to redefine the interface:
public interface IVector<T, TScalar>
where T : IVector<T, TScalar>
{
T Add(T addend);
}
public struct Vector3f : IVector<Vector3f, float>
{
public Vector3f Add(Vector3f addend)
{
}
}
EDIT:
As Anthony Pegram points out, there are holes in this pattern. Nonetheless, it's widely used. For example:
struct Int32 : IComparable<Int32> ...
For more information, here is a link to Eric Lippert's article Curiouser and curiouser about this pattern.
Others have noted a difficulty with your interface, which is that there isn't any way to cleanly identify classes which can operate mutually with other items of their own class; this difficulty stems in some measure from the fact that such classes violate the Liskov Substitution Principle; if a class accepts two objects of type baseQ and expects to have one operate on each other, then the LSP would dictate that one should be able to replace one of the baseQ objects with a derivedQ. This in turn implies that a baseQ should operate on a derivedQ, and a derivedQ should operate on a baseQ. More broadly, any derivative of baseQ should operate on any other derivative of baseQ. The interface is thus not covariant, nor contravariant, nor invariant, but rather non-generic.
If the reason one wishes to use generics is to allow one's interfaces to act upon structs without boxing, the pattern given in phoog's answer is a good one. One generally shouldn't worry about imposing reflexive constraints on type parameters, since the purpose of the interfaces is to be used not as constraints, rather than variable or parameter types, and the necessary conditions can be imposed by the routine using the constraints (e.g. VectorList<T,U> where T:IVector<T,U>).
Incidentally, I should mention that the behavior of interface types used as constraints is very different from that of variables and parameters of interface type. For every struct type, there is another type derived from ValueType; this latter type will exhibit reference semantics rather than value semantics. If a variable or parameter of a value type is passed to a routine or stored in a variable that requires a class type, the system will copy the contents to a new class object derived from ValueType. If the struct in question is immutable, any and all such copies will always hold the same content as the original and each other, and may thus be regarded as being generally semantically equivalent to the original. If, however, the struct in question is mutable, such copying operations may yield semantics very different from what might be expected. While there are times it can be useful to have interface methods mutate structs, such interfaces must be used with extreme care.
For example, consider the behavior of List<T>.Enumerator, which implements IEnumerator<T>. Copying one variable of type List<T>.Enumerator to another of that same type will take a "snapshot" of the list position; calling MoveNext on one variable will not affect the other. Copying such a variable to one of type Object, IEnumerator<T>, or an interface derived from IEnumerator<T>, will also take a shapshot, and as above calling MoveNext on either the original or the new variable will leave the other unaffected. On the other hand, copying one variable of type Object, IEnumerator<T>, or an interface derived from IEnumerator<T> to another which is also one of those types (same or different), will not take a snapshot, but simply copy a reference to the earlier-created snapshot.
There are times it can be useful to have all copies of a variable be semantically equivalent. There are other times it can be useful for them to be semantically detached. Unfortunately, if one isn't careful, one may end up with an odd mish-mosh of semantics which could only be described as "semantically confusing".
Related
Given the below:
Is it truly the case that if an IReadOnly(of T) was conceived from an extant MutableEquivalent(of T), that simply casting to the mutable version allows full access, and changes to an object others may rely on to have static elements/count? The output below shows my "THIRD INJECTION" string, despite iterating through a read only collection. Is it just manners and self control that prohibit casting a readonly collection down? Are you supposed to see the interface provided, and bear its restrictions, cast-invariant, due to type alone? Thanks for any clarification on what this interface and others like it truly promise/guarantee.
EDIT- This is not a duplicate of IReadOnlyCollection<T> vs List.AsReadOnly() since I didn't mention List.AsReadOnly() in my question, nor IReadOnlyCollection. Those were introduced by responders. This was a question on underlying mutable list exposure when behind an IReadOnly interface. There are some overlaps in some comments, but a question such as "What does IReadOnly actually do for its underlying mutable List(of T)?" duplicates the spirit of my question. Not "What is the difference between these two entities pertaining to read only?", since I only mentioned one.
static class Program
{
public static void Main()
{
List<string> hack = (List<string>) READONLY;
hack.Add("THIRD INJECTION");
foreach (var s in READONLY)
{
Console.WriteLine(s);
}
}
public static readonly IReadOnlyList<string> READONLY = new List<string>{"#0", "#1"};
}
From your comment:
I didn't realize the interface was more a loose protection for a programmer rather than a 'const'-esque' barrier to mutation. … I assumed, incorrectly, that a downcast from a readonly to mutable would be an invalid cast.
An interface isn't intended as "protection" of any sort, at all. It is simply a promise to implement specific features.
The benefit of IReadOnlyList<T> is one of semantics and now, with generic type variance in C#, flexibility. The semantic benefit allows you to expose a list in a way that expresses the intent to only read it and not modify it.
The flexibility comes in, because the type parameter can be made covariant. This allows implicit conversions from IReadOnlyList<T1> to IReadOnlyList<T2> where T1 inherits T2.
It is up to the implementor of the interface to decide whether true immutability is provided or not. If you want a collection to be truly immutable, you would use ReadOnlyCollection<T> as the implementation for IReadOnlyList<T>, instead of List<T>. You can pass any IList<T> implementation to the ReadOnlyCollection<T> constructor, and the new object will expose that IList<T> object's data without allowing modification (directly…you can always, of course, cheat with reflection, even with a object that is truly immutable and not just a wrapper like ReadOnlyCollection<T>).
With any interface, you are always only dealing with a specific object, which has a specific type, that type always implements some functionality, and can always be cast to the original type, as well as any other interfaces it might implement.
It would be a mistake to think of interfaces as in any significant way a form of protection. They aren't. They just express what an object is able to do.
The underlying collection of READONLY is a mutable list, this is the reason that the cast actually succeeds when creating the hack variable. READONLY is read-only for any of its consumers, but the underlying list can still be mutated.
UPDATED: As Sir Rufo pointed out, exposing the list by way of list.AsReadOnly() will prevent hard casting.
I thought that I knew how to handle structures, since I have programmed in C for years. However, I have come across this struct definition in a C# program that I am attempting to understand. It is populated with booleans and each instance of the struct is going to be a cell in an array (not shown here). I expect that the override in line 3 is used to override a method "ToString()" in a base class.
public struct Cell
{
public bool occupied;
public Cell(bool occupied) { this.occupied = occupied; }
public override string ToString() { return occupied ? "x" : "."; }
}
I understand the first line above. I believe that I am confused about the use of methods in structures, as I am assuming that the second and third lines in the above struct definition are methods. The second line is very confusing to me.
Thank You
Tom
The second line in the struct is the constructor of the struct (so yeah, it's basically a method) which takes a boolean as a parameter and assigns the value passed in to the "occupied" field.
The third line is an override of the ToString method, which is inherited by everything because it's a built-in method of the Object class, which is a superclass of every other object that exists in C#. By default, it simply outputs the fully-qualified class/struct name.
The struct of C# has little to do with the struct from C. In .NET, all (for practical purposes) entities inherit from Object.
It does not matter if they are classes (reference types) or structs (value types); both can have methods, constructors, properties, attributes etc.. The only limitation is that you cannot extend a concrete value type (that is, you cannot inherit from a struct), since their memory footprint and type is predefined when unboxed. Therefore, you can think of all value types being "final".
Also, you can have constructors on structs (which is what you're seeing in the middle of your example code). Note, however, that a struct always also has an implicit "default constructor" with no arguments, which initializes the data to all binary 0.
What exactly is your confusion? You have two good guesses about lines #2 and #3, which can be easily verified with a simple test case.
Yes, the second line is a constructor, which receives a boolean and initializes a field's value.
The third line, as you guessed, is also a method which overrides the base ToString. In this case, since there's no explicit base class, the type extends the methods found in System.Object, known colloquially in C# as object. object's implementation would simply print out the type name ("MyNamespace.Cell"), but this implementation overrides it with the contents of the boolean field.
Structs and classes are very similar to use in C#. So your struct can have methods and a constructor. But there are a few differences. For example: A struct is called by value, a class by reference.
To choose the right one of these options look here:
https://msdn.microsoft.com/en-us/library/ms229017%28v=vs.110%29.aspx
Here the differences are explained:
Structs versus classes
Main difference between struct and class in c# is that class instances are reference types, while struct instances are value types (stored in the stack, rather than the heap).
Second line in your code is just a simple constructor. Structs may have constructor as long as they are not empty constructors. (See https://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx)
Third line is overriding the base Object class method ToString().
Structs may define methods, there's nothing wrong with it.
For additional information about structs, make sure to check out MSDN docs about structs
So as you may know, arrays in C# implement IList<T>, among other interfaces. Somehow though, they do this without publicly implementing the Count property of IList<T>! Arrays have only a Length property.
Is this a blatant example of C#/.NET breaking its own rules about the interface implementation or am I missing something?
So as you may know, arrays in C# implement IList<T>, among other interfaces
Well, yes, erm no, not really. This is the declaration for the Array class in the .NET 4 framework:
[Serializable, ComVisible(true)]
public abstract class Array : ICloneable, IList, ICollection, IEnumerable,
IStructuralComparable, IStructuralEquatable
{
// etc..
}
It implements System.Collections.IList, not System.Collections.Generic.IList<>. It can't, Array is not generic. Same goes for the generic IEnumerable<> and ICollection<> interfaces.
But the CLR creates concrete array types on the fly, so it could technically create one that implements these interfaces. This is however not the case. Try this code for example:
using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) {
var goodmap = typeof(Derived).GetInterfaceMap(typeof(IEnumerable<int>));
var badmap = typeof(int[]).GetInterfaceMap(typeof(IEnumerable<int>)); // Kaboom
}
}
abstract class Base { }
class Derived : Base, IEnumerable<int> {
public IEnumerator<int> GetEnumerator() { return null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
The GetInterfaceMap() call fails for a concrete array type with "Interface not found". Yet a cast to IEnumerable<> works without a problem.
This is quacks-like-a-duck typing. It is the same kind of typing that creates the illusion that every value type derives from ValueType which derives from Object. Both the compiler and the CLR have special knowledge of array types, just as they do of value types. The compiler sees your attempt at casting to IList<> and says "okay, I know how to do that!". And emits the castclass IL instruction. The CLR has no trouble with it, it knows how to provide an implementation of IList<> that works on the underlying array object. It has built-in knowledge of the otherwise hidden System.SZArrayHelper class, a wrapper that actually implements these interfaces.
Which it doesn't do explicitly like everybody claims, the Count property you asked about looks like this:
internal int get_Count<T>() {
//! Warning: "this" is an array, not an SZArrayHelper. See comments above
//! or you may introduce a security hole!
T[] _this = JitHelpers.UnsafeCast<T[]>(this);
return _this.Length;
}
Yes, you can certainly call that comment "breaking the rules" :) It is otherwise darned handy. And extremely well hidden, you can check this out in SSCLI20, the shared source distribution for the CLR. Search for "IList" to see where the type substitution takes place. The best place to see it in action is clr/src/vm/array.cpp, GetActualImplementationForArrayGenericIListMethod() method.
This kind of substitution in the CLR is pretty mild compared to what happens in the language projection in the CLR that allows writing managed code for WinRT (aka Metro). Just about any core .NET type gets substituted there. IList<> maps to IVector<> for example, an entirely unmanaged type. Itself a substitution, COM doesn't support generic types.
Well, that was a look at what happens behind the curtain. It can be very uncomfortable, strange and unfamiliar seas with dragons living at the end of the map. It can be very useful to make the Earth flat and model a different image of what's really going on in managed code. Mapping it to everybody favorite answer is comfortable that way. Which doesn't work so well for value types (don't mutate a struct!) but this one is very well hidden. The GetInterfaceMap() method failure is the only leak in the abstraction that I can think of.
New answer in the light of Hans's answer
Thanks to the answer given by Hans, we can see the implementation is somewhat more complicated than we might think. Both the compiler and the CLR try very hard to give the impression that an array type implements IList<T> - but array variance makes this trickier. Contrary to the answer from Hans, the array types (single-dimensional, zero-based anyway) do implement the generic collections directly, because the type of any specific array isn't System.Array - that's just the base type of the array. If you ask an array type what interfaces it supports, it includes the generic types:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Output:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
For single-dimensional, zero-based arrays, as far as the language is concerned, the array really does implement IList<T> too. Section 12.1.2 of the C# specification says so. So whatever the underlying implementation does, the language has to behave as if the type of T[] implements IList<T> as with any other interface. From this perspective, the interface is implemented with some of the members being explicitly implemented (such as Count). That's the best explanation at the language level for what's going on.
Note that this only holds for single-dimensional arrays (and zero-based arrays, not that C# as a language says anything about non-zero-based arrays). T[,] doesn't implement IList<T>.
From a CLR perspective, something funkier is going on. You can't get the interface mapping for the generic interface types. For example:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Gives an exception of:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
So why the weirdness? Well, I believe it's really due to array covariance, which is a wart in the type system, IMO. Even though IList<T> is not covariant (and can't be safely), array covariance allows this to work:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... which makes it look like typeof(string[]) implements IList<object>, when it doesn't really.
The CLI spec (ECMA-335) partition 1, section 8.7.1, has this:
A signature type T is compatible-with a signature type U if and only if at least one of the following holds
...
T is a zero-based rank-1 array V[], and U is IList<W>, and V is array-element-compatible-with W.
(It doesn't actually mention ICollection<W> or IEnumerable<W> which I believe is a bug in the spec.)
For non-variance, the CLI spec goes along with the language spec directly. From section 8.9.1 of partition 1:
Additionally, a created vector with element type T, implements the interface System.Collections.Generic.IList<U>, where U := T. (§8.7)
(A vector is a single-dimensional array with a zero base.)
Now in terms of the implementation details, clearly the CLR is doing some funky mapping to keep the assignment compatibility here: when a string[] is asked for the implementation of ICollection<object>.Count, it can't handle that in quite the normal way. Does this count as explicit interface implementation? I think it's reasonable to treat it that way, as unless you ask for the interface mapping directly, it always behaves that way from a language perspective.
What about ICollection.Count?
So far I've talked about the generic interfaces, but then there's the non-generic ICollection with its Count property. This time we can get the interface mapping, and in fact the interface is implemented directly by System.Array. The documentation for the ICollection.Count property implementation in Array states that it's implemented with explicit interface implementation.
If anyone can think of a way in which this kind of explicit interface implementation is different from "normal" explicit interface implementation, I'd be happy to look into it further.
Old answer around explicit interface implementation
Despite the above, which is more complicated because of the knowledge of arrays, you can still do something with the same visible effects through explicit interface implementation.
Here's a simple standalone example:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}
IList<T>.Count is implemented explicitly:
int[] intArray = new int[10];
IList<int> intArrayAsList = (IList<int>)intArray;
Debug.Assert(intArrayAsList.Count == 10);
This is done so that when you have a simple array variable, you don't have both Count and Length directly available.
In general, explicit interface implementation is used when you want to ensure that a type can be used in a particular way, without forcing all consumers of the type to think about it that way.
Edit: Whoops, bad recall there. ICollection.Count is implemented explicitly. The generic IList<T> is handled as Hans descibes below.
Explicit interface implementation. In short, you declare it like void IControl.Paint() { } or int IList<T>.Count { get { return 0; } }.
It's no different than an explicit interface implementation of IList. Just because you implement the interface doesn't mean its members need to appear as class members. It does implement the Count property, it just doesn't expose it on X[].
With reference-sources being available:
//----------------------------------------------------------------------------------------
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
//
// The methods on this class must be written VERY carefully to avoid introducing security holes.
// That's because they are invoked with special "this"! The "this" object
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
// see a lot of expressions that cast "this" "T[]".
//
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
// ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it.
//
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
//----------------------------------------------------------------------------------------
sealed class SZArrayHelper {
// It is never legal to instantiate this class.
private SZArrayHelper() {
Contract.Assert(false, "Hey! How'd I get here?");
}
/* ... snip ... */
}
Specifically this part:
the interface stub dispatcher treats this as a special case, loads up
SZArrayHelper, finds the corresponding generic method (matched simply
by method name), instantiates it for type and executes it.
(Emphasis mine)
Source (scroll up).
Okay. I've read this post, and I'm confused on how it applies to my example (below).
class Foo
{
public static implicit operator Foo(IFooCompatible fooLike)
{
return fooLike.ToFoo();
}
}
interface IFooCompatible
{
Foo ToFoo();
void FromFoo(Foo foo);
}
class Bar : IFooCompatible
{
public Foo ToFoo()
{
return new Foo();
}
public void FromFoo(Foo foo)
{
}
}
class Program
{
static void Main(string[] args)
{
Foo foo = new Bar();
// should be the same as:
// var foo = (new Bar()).ToFoo();
}
}
I have thoroughly read the post I linked to. I have read section 10.10.3 of the C# 4 specification. All of the examples given relate to generics and inheritance, where the above does not.
Can anyone explain why this is not allowed in the context of this example?
Please no posts in the form of "because the specification says so" or that simply quote the specification. Obviously, the specification is insufficient for my understanding, or else I would not have posted this question.
Edit 1:
I understand that it's not allowed because there are rules against it. I am confused as to why it's not allowed.
I understand that it's not allowed because there are rules against it. I am confused as to why it's not allowed.
The general rule is: a user defined conversion must not in any way replace a built-in conversion. There are subtle ways that this rule can be violated involving generic types, but you specifically say that you are not interested in generic type scenarios.
You cannot, for example, make a user-defined conversion from MyClass to Object, because there already is an implicit conversion from MyClass to Object. The "built in" conversion will always win, so allowing you to declare a user-defined conversion would be pointless.
Moreover, you cannot even make a user-defined implicit conversion that replaces a built-in explicit conversion. You cannot, for example, make a user-defined implicit conversion from Object to MyClass because there already is a built-in explicit conversion from Object to MyClass. It is simply too confusing to the reader of the code to allow you to arbitrarily reclassify existing explicit conversions as implicit conversions.
This is particularly the case where identity is involved. If I say:
object someObject = new MyClass();
MyClass myclass = (MyClass) someObject;
then I expect that this means "someObject actually is of type MyClass, this is an explicit reference conversion, and now myclass and someObject are reference equal". If you were allowed to say
public static implicit operator MyClass(object o) { return new MyClass(); }
then
object someObject = new MyClass();
MyClass myclass = someObject;
would be legal, and the two objects would not have reference equality, which is bizarre.
Already we have enough rules to disqualify your code, which converts from an interface to an unsealed class type. Consider the following:
class Foo { }
class Foo2 : Foo, IBlah { }
...
IBlah blah = new Foo2();
Foo foo = (Foo) blah;
This works, and one reasonably expects that blah and foo are reference equals because casting a Foo2 to its base type Foo does not change the reference. Now suppose this is legal:
class Foo
{
public static implicit operator Foo(IBlah blah) { return new Foo(); }
}
If that is legal then this code is legal:
IBlah blah = new Foo2();
Foo foo = blah;
we have just converted an instance of a derived class to its base class but they are not reference equal. This is bizarre and confusing, and therefore we make it illegal. You simply may not declare such an implicit conversion because it replaces an existing built-in explicit conversion.
So alone, the rule that you must not replace any built-in conversion by any user-defined conversion is sufficient to deny you the ability to create a conversion that takes an interface.
But wait! Suppose Foo is sealed. Then there is no conversion between IBlah and Foo, explicit or implicit, because there cannot possibly by a derived Foo2 that implements IBlah. In this scenario, should we allow a user-defined conversion between Foo and IBlah? Such a user-defined conversion cannot possibly replace any built-in conversion, explicit or implicit.
No. We add an additional rule in section 10.10.3 of the spec that explicitly disallows any user-defined conversion to or from an interface, regardless of whether this replaces or does not replace a built-in conversion.
Why? Because one has the reasonable expectation that when one converts a value to an interface, that you are testing whether the object in question implements the interface, not asking for an entirely different object that implements the interface. In COM terms, converting to an interface is QueryInterface -- "do you implement this interface?" -- and not QueryService -- "can you find me someone who implements this interface?"
Similarly, one has a reasonable expectation that when one converts from an interface, one is asking whether the interface is actually implemented by an object of the given target type, and not asking for an object of the target type that is entirely different from the object that implements the interface.
Thus, it is always illegal to make a user-defined conversion that converts to or from an interface.
However, generics muddy the waters considerably, the spec wording is not very clear, and the C# compiler contains a number of bugs in its implementation. Neither the spec nor the implementation are correct given certain edge cases involving generics, and that presents a difficult problem for me, the implementer. I am actually working with Mads today on clarifying this section of the spec, as I am implementing it in Roslyn next week. I will attempt to do so with as few breaking changes as possible, but a small number may be necessary in order to bring the compiler behaviour and the specification language in line with each other.
The context of your example, it won't work again because the implicit operator has been placed against an interface... I'm not sure how you think your sample is different to the one you linked other than you try to get one concrete type across to another via an interface.
There is a discussion on the topic here on connect:
http://connect.microsoft.com/VisualStudio/feedback/details/318122/allow-user-defined-implicit-type-conversion-to-interface-in-c
And Eric Lippert might have explained the reason when he said in your linked question:
A cast on an interface value is always treated as a type test because
it is almost always possible that the object really is of that type
and really does implement that interface. We don't want to deny you
the possibility of doing a cheap representation-preserving conversion.
It seems to be to do with type identity. Concrete types relate to each other via their hierarchy so type identity can be enforced across it. With interfaces (and other blocked things such as dynamic and object) type identity becomes moot because anyone/everyone can be housed under such types.
Why this is important, I have no idea.
I prefer explicit code that shows me I am trying to get a Foo from another that is IFooCompatible, so a conversion routine that takes a T where T : IFooCompatible returning Foo.
For your question I understand the point of discussion, however my facetious response is if I see code like Foo f = new Bar() in the wild I would very likely refactor it.
An alternative solution:
Don't over egg the pudding here:
Foo f = new Bar().ToFoo();
You have already exposed the idea that Foo compatible types implement an interface to achieve compatibility, use this in your code.
Casting versus converting:
It is also easy to get wires crossed about casting versus converting. Casting implies that type information is integral between the types you are casting around, hence casting doesn't work in this situation:
interface IFoo {}
class Foo : IFoo {}
class Bar : IFoo {}
Foo f = new Foo();
IFoo fInt = f;
Bar b = (Bar)fInt; // Fails.
Casting understands the type hierarchy and the reference of fInt cannot be cast to Bar as it is really Foo. You could provide a user-defined operator to possibly provide this:
public static implicit operator Foo(Bar b) { };
And doing this in your sample code works, but this starts to get silly.
Converting, on the other hand, is completely independent of the type hierarchy. Its behaviour is entirely arbitrary - you code what you want. This is the case you are actually in, converting a Bar to a Foo, you just happen to flag convertible items with IFooCompatible. That interface doesn't make casting legal across disparate implementing classes.
As for why interfaces are not allowed in user-defined conversion operators:
Why can't I use interface with explicit operator?
The short version is that it's disallowed so that the user can be
certain that conversions between reference types and interfaces
succeed if and only if the reference type actually implements that
interface, and that when that conversion takes place that the same
object is actually being referenced.
Okay, here's an example of why I believe the restriction is here:
class Foo
{
public static implicit operator Foo(IFooCompatible fooLike)
{
return fooLike.ToFoo();
}
}
class FooChild : Foo, IFooCompatible
{
}
...
Foo foo = new FooChild();
IFooCompatible ifoo = (IFooCompatible) foo;
What should the compiler do here, and what should happen at execution time? foo already refers to an implementation of IFooCompatible, so from that point of view it should just make it a reference conversion - but the compiler doesn't know that's the case, so should it actually just call the implicit conversion?
I suspect the basic logic is: don't allow an operator to defined which could conflict with an already-valid conversion based on the execution-time type. It's nice for there to be exactly zero or one possible conversion from an expression to a target type.
(EDIT: Adam's answer sounds like it's talking about pretty much the same thing - feel free to regard my answer as merely an example of his :)
What would probably be helpful here would be for .net to provide a "clean" way to associate an interface with a static type, and have various types of operations on interface types map to corresponding operations on the static type. In some scenarios this can be accomplished with extension methods, but that is both ugly and limited. Associating with interfaces with static classes could offer some significant advantages:
Presently, if an interface wishes to offer consumers multiple overloads of a function, every implementation must implement every overload. Pairing a static class with an interface, and allowing that class to declare methods in the style of extension methods would allow consumers of the class to use overloads provided by the static class as though they were part of the interface, without requiring implementers to provide them. This can be done with extension methods, but it requires that the static method be manually imported on the consumer side.
There are many circumstances where an interface will have some static methods or properties which are very strongly associated with it (e.g. `Enumerable.Empty`). Being able to use the same name for the interface and the 'class' of the associated properties would seem cleaner than having to use separate names for the two purposes.
It would provide a path to supporting optional interface members; if a member exists in an interface but not an implementation, the vtable slot could be bound to a static method. This would be an extremely useful feature, since it would allow interfaces to be extended without breaking existing implementations.
Given that unfortunately such a feature only exists to the extent necessary to work with COM objects, the best alternative approach I can figure would be to define a struct type which holds a single member of interface type, and implements the interface by acting as a proxy. Conversion from the interface to the struct would not require creation of an extra object on the heap, and if functions were to provide overloads which accepted that struct, they could convert back to the interface type in a manner whose net result would be value-preserving and not require boxing. Unfortunately, passing such a struct to a method which used the interface type would entail boxing. One could limit the depth of boxing by having the struct's constructor check whether the interface-type object that was passed to it was a nested instance of that struct, and if so unwrap one layer of boxing. That could be a bit icky, but might be useful in some cases.
I tried to create a ValueType.
I understand that creating a struct would help me.
I also tried to derive a type from System.ValueType which is an abstract class.
But I got a compiler error message
".. cannot derive from special class System.ValueType"
When I see the metadata of ValueType, it looks to be a regular abstract class. Any non sealed class should be derivable. But System.ValueType is not a sealed class.
What made it special?
Is it the C# compiler that senses it as special?
If so, is it recommended as a rule for compiler design? I mean is it part of Common Language Specification?
ValueType is a little white lie.
The built-in numeric types (int, long, byte), char, enums and structs are all value types.
This means that they have a different concepts of identity and equivalence to object types. If I do x = y and x and y are reference types, then x and y now point to precisely the same object. However, if I do x = y and x and y are value types, then x and y are now two completely different objects that happen to be identical. (This is also reflected in == and Equals, though that can be overridden).
(This is where people get sidetracked by talking about the stack and the heap, if they haven't already, really that's an implementation detail and while important, is not the point of the distinction between value and reference types).
Now, mostly this is all and good but one thing about reference types is that they all benefit from inheriting from System.Object. The value type int doesn't really, and that's good too as it's much better in many ways that it just be four bytes of memory handled by the lovely CPU instructions that are so good at doing so. Still, it's sometimes useful to be able to treat an int as if it also inherited from System.Object, and so you can.
Of course, this means that you may do things with int that only make sense to do on a System.Object, so when you do so the int is "boxed" and can then be "unboxed" again.
This is great, but what if we wanted to do something specific to value types? More to the point, what if the designers of the CLR did (in particular, they wanted a GetHashCode for value types that related to the value-based equivalence descibed above, rather than the identity-based equivalence that objects have)?
For this purpose we have ValueType. The system treats all value types as inheriting from this class, which in turn inherits from Object. Enum in turn inherits from value type and all enum types inherit from it, allowing some common functionality across all enums.
So, if you ever want to treat a superclass of all value types, use ValueType, but if you want to actually create a value type, create a struct or an enum as appropriate.
The Common Type System explanation:
A structure is a value type that derives implicitly from System.ValueType, which in turn is derived from System.Object. A structure is very useful for representing values whose memory requirements are small, and for passing values as by-value parameters to methods that have strongly typed parameters. In the .NET Framework class library, all primitive data types (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, and UInt64) are defined as structures.
Like classes, structures define both data (the fields of the structure) and the operations that can be performed on that data (the methods of the structure). This means that you can call methods on structures, including the virtual methods defined on the System.Object and System.ValueType classes, and any methods defined on the value type itself. In other words, structures can have fields, properties, and events, as well as static and nonstatic methods. You can create instances of structures, pass them as parameters, store them as local variables, or store them in a field of another value type or reference type. Structures can also implement interfaces.
Value types also differ from classes in several respects. First, although they implicitly inherit from System.ValueType, they cannot directly inherit from any type. Similarly, all value types are sealed, which means that no other type can be derived from them. They also do not require constructors.
For each value type, the common language runtime supplies a corresponding boxed type, which is a class that has the same state and behavior as the value type. An instance of a value type is boxed when it is passed to a method that accepts a parameter of type System.Object. It is unboxed (that is, converted from an instance of a class back to an instance of a value type) when control returns from a method call that accepts a value type as a by-reference parameter. Some languages require that you use special syntax when the boxed type is required; others automatically use the boxed type when it is needed. When you define a value type, you are defining both the boxed and the unboxed type.
The strangeness of ValueType is to allow the above to happen.
Structures are value types. Value types are special because they are allocated on the stack rather than the heap. To "inherit" from ValueType, you must create a struct.
Not being able to derive from ValueType is specific to the C# compiler. If we look at managed C++ code:
value class Foo {};
value class Foo : System::ValueType {};
Both of these compile and are identical. Of course,
ref class Foo : System::ValueType {};
Will give error C3050: a ref class cannot inherit from 'System::ValueType'.
Not sure what other compilers allow.
If you want to derive from ValueType in C#, use struct and not class, and the compiler takes care of it.
C# does not allow value types to inherit from other classes. Value types (struct) can implement interfaces.
you cannot subclass ValueType directly. All value types derives from ValueType implicitly. Unlike with reference types, you cannot derive a new type from a value type. However, like reference types, structs can implement interfaces.
see MSDN to know more
A 'class' extends 'System.Object', a 'struct' extends 'System.ValueType'. If you could make a class extend 'System.ValueType', then there wouldn't be much point to the 'struct' keyword.
Yes
Yes. There should only be one way to accomplish any given thing. As soon as two methods of doing something are provided, you've just make everything more complicated. General rule.
This is what perplexes me... Enum is derived from ValueType. Which makes me think the above is just a compiler restriction.
[Serializable, ComVisible(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
...
}