As requested, I'm answering an edited version of the question is a separate answer. This question is indeed radically different from the original question. :-)
All the problem is the misuse of the non-generic method of generic interface. Here is how a fixed version of the code might look (and it will work, of course):
public class DerivedSomething : ISomething<int> {
public void DoSomething(int item) {
}
public bool MustStop {
get { return true; }
}
}
public interface ISomething<T> {
void DoSomething(T item);
bool MustStop { get; }
}
class Test {
void TestMethod() {
DerivedSomething thing = new DerivedSomething();
if (thing.MustStop)
Console.WriteLine("Stop!");
else
Console.WriteLine("Don't stop!");
}
}
I also renamed
Something
to
ISomething
to meet (good) Microsoft naming conventions for interfaces. There is certain confusion due to the fact you miss one important step which partially defeats the purpose of generic interfaces. To make the inheritance chain really practical, you need to make is like this: generic interface => generic (possibly abstract) class implementing methods agnostic to generic parameters => set of complete implementation classes — using the idea shown in my previous answer. The term "
class
" could be replaces with "
struct
".
[EDIT #1]
This is amazing: I just made a real "Freudian slip" (
http://en.wikipedia.org/wiki/Freudian_slip[
^])!
In the above paragraph, I wanted to type "(good) Microsoft naming conventions", but typed "goof Microsoft naming conventions"!
No, they are really good, not goof; and I'm using them.
[END EDIT #1]
[EDIT #2]
After some thinking, I realized that I can see two more problems in the code above. I explained above, that 1) missing intermediate implementation class implementing just non-generic part of the interface; in this way you would not repeat implementation of those non-generic methods/properties in each of generic type-specific implementation. Two remaining problems are: 2) interfaces are designed to be use during run-time; remove all interfaces from your code — it will work in exact same way, why writing them? you should really use your classed via interfaces; 3) you use implicit interface implementation (via "
public
"); but explicit interface implementation is much clearer.
My fix of the problems (2) and (3) required change in usage but then the use of interfaces is really justified in a practically beneficial way, and lack of code reuse if fixed (the schema you want is useful only when you need to have more than one class like
DerivedSomething
, but if you try to write more classes you will see that
MustStop
implementation is not reused); so, the code fixing all together will look like this:
public interface IAgnostic {
bool MustStop { get; }
}
public interface ISomething<T> : IAgnostic {
void DoSomething(T item);
}
abstract class Agnostic : IAgnostic {
bool IAgnostic.MustStop {
get { return true; }
}
}
class DerivedSomething : Agnostic, IAgnostic, ISomething<int> {
void ISomething<int>.DoSomething(int item) {
}
}
class DerivedSomethingElse : Agnostic, IAgnostic, ISomething<int> {
void ISomething<int>.DoSomething(int item) {
}
}
class Test {
void TestMethod() {
DerivedSomething thing = new DerivedSomething();
ISomething<int> somethigReferenced = thing;
if (somethigReferenced.MustStop)
Console.WriteLine("Stop!");
else
Console.WriteLine("Don't stop!");
}
}
I fix to the lack of code reuse is done via additional interface
IAgnostic
that is, agnostic to generic parameters and additional abstract implementation class
IAgnostic
. The fix is demonstrated by having two different terminal completely implementing classes,
DerivedSomething
and
DerivedSomethingElse
.
Now it's really right.
[END EDIT #2]
Now, I gave you the resolution which does not even touch the root topic collectively named "
covariance and contravariance". To really understand these issues you really need to learn this topic. In C# practice, it's mostly about new features introduced to C# v.4 in comparison with prior versions.
So, try to read and understand this:
http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29[
^],
http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx[
^] (you really need to read all parts of it, but it needs some effort to find them; the navigation in this blog really needs improvement!),
http://blogs.msdn.com/b/ericlippert/archive/2007/10/26/covariance-and-contravariance-in-c-part-five-interface-variance.aspx[
^],
http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx[
^].
Just to give you the idea how much C# and .NET are lost in covariance/contravariance issues:
string[] strings = new string[] { "1", "2", };
object[] objectsobjects = strings;
System.Collections.Generic.List<string> strList = new System.Collections.Generic.List<string>();
System.Collections.Generic.List<object> objList = strList;
The covariance/contravariance issues come into play each time there is a class using instances of other classes when using and used types are derivable. So, the issues are about arrays, generic containers and generic delegates. This goes beyond the casting topics we're discussing here.
—SA