I have been confused by the following code
class A
{
public void Abc(int q)
{
Console.Write("A");
}
}
class B : A
{
public void Abc(double p)
{
Console.Write("B");
}
}
...
var b = new B();
b.Abc((int)1);
The result of code execution is "B" written to console.
In fact the B class contains two overloads of Abc method, the first for int parameter, the second one for double. Why the compiler use a double version for an integer argument?
Be careful the method abc(double) doesn't shadow or override the method abc(int)
Since the compiler can implicitly convert the int to double, it chooses the B.Abc method. This is explained in this post by Jon Skeet (search for "implicit"):
The target of the method call is an expression of type Child, so the
compiler first looks at the Child class. There's only one method
there, and it's applicable (there's an implicit conversion from int to
double) so that's the one that gets picked. The compiler doesn't
consider the Parent method at all.
The reason for this is to reduce the risk of the brittle base class
problem...
More from Eric Lippert
As the standard says, “methods in a base class are not candidates if any method in a derived class is applicable”.
In other words, the overload resolution algorithm starts by searching
the class for an applicable method. If it finds one then all the other
applicable methods in deeper base classes are removed from the
candidate set for overload resolution. Since Delta.Frob(float) is
applicable, Charlie.Frob(int) is never even considered as a candidate.
Only if no applicable candidates are found in the most derived type do
we start looking at its base class.
Things get a little more interesting if we extend the example in your question with this additional class that descends from A:
class C : A {
public void Abc(byte b) {
Console.Write("C");
}
}
If we execute the following code
int i = 1;
b.Abc((int)1);
b.Abc(i);
c.Abc((int)1);
c.Abc(i);
the results are BBCA. This is because in the case of the B class, the compiler knows it can implicitly cast any int to double. In the case of the C class, the compiler knows it can cast the literal int 1 to a byte (because the value 1 fits in a byte) so C's Abc method gets used. The compiler, however, can't implicitly cast any old int to a byte, so c.Abc(i) can't use C's Abc method. It must use the parent class in that case.
This page on Implicit Numeric Conversions shows a compact table of which numeric types have implicit conversions to other numeric types.
You get the same functionality even when you define B as:
class B : A
{
public void Abc(object p)
{
Console.Write("B");
}
}
Simply, it's because overload resolution is done by looking at methods defined in the current class. If there are any suitable methods in the current class, it stops looking. Only if there are no suitable matches does it look at base classes
You can take a look at the Overload resolution spec for a detailed explanation.
Different languages (such as C++, Java, or C#) have vastly different overload resolution rules. In C#, the overload was correctly chosen as per the language spec. If you wanted the other overload to be chosen, you have a choice. Remember this:
When a derived class intends to declare another overload for an inherited method, so as to treat all available overloads as equal-rights peers, it must also explicitly override all the inherited overloads with a base call as well.
What is the language design benefit of requiring this exercise?
Imagine that you are using a 3rd party library (say, .NET framework) and deriving from one of its classes. At some point you introduce a private method called Abc (a new, unique name, not an overload of anything). Two years later you upgrade the 3rd party library version without noticing that they also added a method, accessible to you and called, regrettably, Abc, except that it has a different parameter type somewhere (so the upgrade doesn't alert you with a compile time error) and it behaves subtly differently or maybe even has a different purpose altogether. Do you really want one half of your private calls to Abc to be silently redirected to the 3rd party Abc? In Java, this may happen. In C# or C++, this isn't going to happen.
The upside of the C# way is that it's somewhat easier, for a redistributed library, to add functionality while rigorously keeping backward compatibility. In two ways actually:
You won't ever mess with your customers' private method calls inside their own code.
You won't ever break your customers by adding a new uniquely named method, although you must still think twice before adding an overload of YOUR own existing method.
The downside of the C# way is that it cuts a hole into the OOP philosophy of overriding methods ever changing only the implementation, but not the API of a class.
Related
Consider the following snippet of code:
using System;
class Base
{
public virtual void Foo(int x)
{
Console.WriteLine("Base.Foo(int)");
}
}
class Derived : Base
{
public override void Foo(int x)
{
Console.WriteLine("Derived.Foo(int)");
}
public void Foo(object o)
{
Console.WriteLine("Derived.Foo(object)");
}
}
public class Program
{
public static void Main()
{
Derived d = new Derived();
int i = 10;
d.Foo(i);
}
}
And the surprising output is:
Derived.Foo(object)
I would expect it to select the overridden Foo(int x) method, since it's more specific. However, C# compiler picks the non-inherited Foo(object o) version. This also causes a boxing operation.
What is the reason for this behaviour?
This is the rule, and you may not like it...
Quote from Eric Lippert
if any method on a more-derived class is an applicable candidate, it
is automatically better than any method on a less-derived class, even
if the less-derived method has a better signature match.
The reason is because the method (that is a better signature match) might have been added in a later version and thereby be introducing a "brittle base class" failure
Note : This is a fairly complicated/in-depth part of the C# specs and it jumps all over the place. However, the main parts of the issue you are experiencing are written as follows
Update
And this is why i like stackoverflow, It is such a great place to learn.
I was quoting the the section on the run time processing of the method call. Where as the question is about compile time overload resolution, and should be.
7.6.5.1 Method invocations
...
The set of candidate methods is reduced to contain only methods from
the most derived types: For each method C.F in the set, where C is the
type in which the method F is declared, all methods declared in a base
type of C are removed from the set. Furthermore, if C is a class type
other than object, all methods declared in an interface type are
removed from the set. (This latter rule only has affect when the
method group was the result of a member lookup on a type parameter
having an effective base class other than object and a non-empty
effective interface set.)
Please see Eric's post answer https://stackoverflow.com/a/52670391/1612975 for a full detail on whats going on here and the appropriate part of the specs
Original
C#
Language Specification
Version 5.0
7.5.5 Function member invocation
...
The run-time processing of a function member invocation consists of
the following steps, where M is the function member and, if M is an
instance member, E is the instance expression:
...
If M is an instance function member declared in a reference-type:
E is evaluated. If this evaluation causes an exception, then no further steps are executed.
The argument list is evaluated as described in §7.5.1.
If the type of E is a value-type, a boxing conversion (§4.3.1) is performed to convert E to type object, and E is considered to be of
type object in the following steps. In this case, M could only be a
member of System.Object.
The value of E is checked to be valid. If the value of E is null, a System.NullReferenceException is thrown and no further steps are
executed.
The function member implementation to invoke is determined:
If the binding-time type of E is an interface, the function member to invoke is the implementation of M provided by the run-time
type of the instance referenced by E. This function member is
determined by applying the interface mapping rules (§13.4.4) to
determine the implementation of M provided by the run-time type of the
instance referenced by E.
Otherwise, if M is a virtual function member, the function member to invoke is the implementation of M provided by the run-time type of
the instance referenced by E. This function member is determined by
applying the rules for determining the most derived implementation
(§10.6.3) of M with respect to the run-time type of the instance
referenced by E.
Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
After reading the specs what's interesting is, if you use an interface which describes the method, the compiler will choose the overload signature, in-turn working as expected
public interface ITest
{
void Foo(int x);
}
Which can be shown here
In regards to the interface, it does make sense when considering the overloading behavior was implemented to protect against Brittle base class
Additional Resources
Eric Lippert, Closer is better
The aspect of overload resolution in C# I want to talk about today is
really the fundamental rule by which one potential overload is judged
to be better than another for a given call site: closer is always
better than farther away. There are a number of ways to characterize
“closeness” in C#. Let’s start with the closest and move our way out:
A method first declared in a derived class is closer than a method first declared in a base class.
A method in a nested class is closer than a method in a containing class.
Any method of the receiving type is closer than any extension method.
An extension method found in a class in a nested namespace is closer than an extension method found in a class in an outer namespace.
An extension method found in a class in the current namespace is closer than an extension method found in a class in a namespace
mentioned by a using directive.
An extension method found in a class in a namespace mentioned in a using directive where the directive is in a nested namespace is closer
than an extension method found in a class in a namespace mentioned in
a using directive where the directive is in an outer namespace.
The accepted answer is correct (excepting the fact that it quotes the wrong section of the spec) but it explains things from the perspective of the specification rather than giving a justification for why the specification is good.
Let's suppose we have base class B and derived class D. B has a method M that takes Giraffe. Now, remember, by assumption, the author of D knows everything about B's public and protected members. Put another way: the author of D must know more than the author of B, because D was written after B, and D was written to extend B to a scenario not already handled by B. We should therefore trust that the author of D is doing a better job of implementing all functionality of D than the author of B.
If the author of D makes an overload of M that takes an Animal, they are saying I know better than the author of B how to deal with Animals, and that includes Giraffes. We we should expect overload resolution when given a call to D.M(Giraffe) to call D.M(Animal), and not B.M(Giraffe).
Let's put this another way: We are given two possible justifications:
A call to D.M(Giraffe) should go to B.M(Giraffe) because Giraffe is more specific than Animal
A call to D.M(Giraffe) should go to D.M(Animal) because D is more specific than B
Both justifications are about specificity, so which justification is better? We're not calling any method on Animal! We're calling the method on D, so that specificity should be the one that wins. The specificity of the receiver is far, far more important than the specificity of any of its parameters. The parameter types are there for tie breaking. The important thing is making sure we choose the most specific receiver because that method was written later by someone with more knowledge of the scenario that D is intended to handle.
Now, you might say, what if the author of D has also overridden B.M(Giraffe)? There are two arguments why a call to D.M(Giraffe) should call D.M(Animal) in this case.
First, the author of D should know that D.M(Animal) can be called with a Giraffe, and it must be written do the right thing. So it should not matter from the user's perspective whether the call is resolved to D.M(Animal) or B.M(Giraffe), because D has been written correctly to do the right thing.
Second, whether the author of D has overridden a method of B or not is an implementation detail of D, and not part of the public surface area. Put another way: it would be very strange if changing whether or not a method was overridden changes which method is chosen. Imagine if you're calling a method on some base class in one version, and then in the next version the author of the base class makes a minor change to whether a method is overridden or not; you would not expect overload resolution in the derived class to change. C# has been designed carefully to prevent this kind of failure.
CUrrently in the process of finally learning C#. But after using C++ and python this is one thing that keeps striking me while writing C#.
C# doesn't have a similar thing to typedef in C++. (Or at least htat's true according to various posts here an other googling results.
Now the first use to "type alias" I can understand (though from experience disagree with - but that's something I can learn to accept).
However there is a different use I've gotten used to a lot, especially after using python for years:
The "Generic" pattern. Where I actually don't care about the type (and say I only care that it can be compared to each other). Now of course a generic class can "do" this, but quite often that is overkill: especially since classes typically have many of those, and they are of little importance to people who USE the class.
An example, say I have a dictionary, which binds "values" to certain "identifiers":
System.Collections.Generics.Dictionary<string, double>
Would be a logical start. However say in the future, when having a clearer picture of the whole application, I wish to change it up. I notice that for calculations I would actually need decimal values instead of floating point - (or maybe even bignums instead of floating points). I'd have to go over my whole code changing this.
Similar to the identifier: strings are "easy" but maybe in the future I don't really want to use such bloated structures. Rather I use something that "can be converted from strings and is unique enough" in my class
Or, hey, in a different future I might wish to not use the generic dictionary: rather I implement a custom one for this class specific.
All these things would require me to change code at many different places. Potential bug-heavy, and thus a maintainer would choose not to change it due to maintenance problems.
In other languages I learned this was solved either by "don't caring" (python) - or by allowing a typedef. And always using that typedef, also in other classes.
What is the idiomatic way to do this in C#? Is it generally accepted to use long "lists" of generic variables in your class definition?
MyClass<A_KeyType, A_ValueType, B_KeyType, B_ValueType, ContainerType>
Seems awkward since not the user, but the maintainer of the class might often know better which to use?
As a very simplistic (silly) example
public class MyClass {
public MyClass() { }
private Systems.Collections.Generics.Dictionary<string, double> Points = new Systems.Collections.Generics.Dictionary<string, double>()
Public void AddPerson(string studentID, double val) {
Points.Add(studentID, val)
}
}
getters, maybe changers etc would all have to explicitly refer to Systems.Collections.Generics.Dictionary<string, double>, even though maybe in the future a studentID would be a simple numeric value or something else. Also the code "using" this, which "gets" the student ID needs to understand it is a string.
In C++ I would parametrize the student type "under" the my class as:
public class MyClass {
typedef string StudentIDType
...
Then I would use that explicit type MyClass.StudentIDType in all situations.
C# doesn't have a similar thing to typedef in C++.
Typedef in C defines a new type. C# has type aliases:
using Frob = System.Collections.Dictionary<System.String, System.String>;
...
Frob f = new Frob();
But these are per file. The named alias is not a member of any namespace or type.
And C# of course allows you to define new types by wrapping old ones:
struct MyOpaqueIdentifier
{
private int id;
public MyOpaqueIdentifier(int id) { this.id = id; }
... now define equality, conversions, etc ...
}
However say in the future, when having a clearer picture of the whole application, I wish to change it up
This is the premature generality error, also known as YAGNI: You Ain't Gonna Need It. There are infinite ways to design programs to be more general, most of which you will never need. The right way to do it is to think hard about what kinds of generalities you're going to need up front, and design them in from the beginning.
Also, remember that Visual Studio has powerful refactoring tools.
What is the idiomatic way to do this in C#? Is it generally accepted to use long "lists" of generic variables in your class definition?
C# lets you express generality in several ways:
base classes -- I can accept anything derived from this class.
interfaces -- I can accept anything that implements this interface.
generics -- the type is parameterized by n other types
generic covariance and contravariance -- a sequence of turtles may be used where a sequence of animals is expected
generic constraints -- a type argument is constrained to a base type, interface, etc.
delegates -- needed functionality that consists of a single method (example: compare two Ts for equality) can be passed in as a delegate to that function, rather than requiring an interface, base type, etc.
It sounds to me like you are considering abusing generics; one of the other approaches is typically used.
Try something like this:
class Program
{
static void Main(string[] args)
{
var obj = new Class1<int, string>();
obj.Dictionary.Add(1, "hello");
}
}
class Class1<Tkey, Tvalue>
{
public Dictionary<Tkey, Tvalue> Dictionary { get; set; }
}
If you want Python way, then use Dictionary<string, object>
You will sacrifice performance and may run into a lot of runtime issues at the cost of minimizing code changes.
I really don't see any value in this. The maintainer still has to go to all the places where you have used float and replace all variable and inputs. You are kinda missing the point of using a strongly typed compiled language.
Your best bet is to create a generic class that wraps your functionality
class MyClass<T>
{
Dictionary<string, T> innerDict;
}
You seem to have a fundamental misunderstanding of generics in C#. They are not meant to allow for easy refactoring the way your C++ with typedef seems prepared for future maintainers to switch the type out. Such a usage seems wrong and, while I don't code in C++, I assume this is less used as a "generic" and more of an "anonymous class" definition. That is to say, you are actually defining a pseudoclass of type StudentIDType whose only property is a string value that you can access directly via the "alias". There are such a thing as anonymous classes in C# (see closures) but they are defined as the input for some function. Rather, the C# method of handling the above situation is to properly reify the pseudoclass to be an explicitly declared class. Such an implementation would look like this:
public class MyClass {
// DO NOT EVER DO THIS
// classes should not contain public classes this is merely the smallest possible example
public class StudentPoints {
public string StudentId { get; set; }
public double PointsValue { get; set; }
}
private IEnumerable<StudentPoints> StudentPointsList = new List<StudentPoints>();
public void AddPerson(StudentPoints studentPoints) {
this.StudentPointsList.Add(studentPoints);
}
}
However, there is an obvious problem with the above which should illustrate to you why the anonymous class is a bad idea. The first is that you've abandoned Dictionary for a simpler List/IEnumerable. This means you can't access values by key without "searching the list" (that is you no longer have a hash table implementation). The second is that you are still bound to change types when refactoring. Unless you can implicitly convert from one to another of the types you switch out then you will still have to change the constructors you use in your code to create StudentPoints. It is unavoidably true that changing the type of something will require code changes for most if not all references to that object. This is exactly what the refactoring tools in Visual Studio are built to help with. However, there is a pattern that you can use that is C# and would allow you to at least "reduce" the pain of the transition so that you don't have to find every instance in the code base before it will compile again. That pattern looks like this and utilizes overloads + the [Obsolete] parameter to indicate you are moving away from the old type and moving to the new:
public class MyClass {
private Dictionary<int, double> StudentPoints = new Dictionary<int, double>(); //was string, double
[Obsolete] // unfixed code will call this
public void AddPerson(string studentId, double val) {
int studentIdInt;
if (Int32.TryParse(studentId, out studentIdInt) {
this.AddPerson(studentIdInt, val);
return;
}
throw new ArgumentException(nameof(studentId), "string not convertable to int");
}
public void AddPerson(int studentId, double val) {
this.StudentList.Add(studentId, val);
}
}
Now the compiler will warn you instead of erroring when you pass a string instead. Issues here are that you may now get a runtime error for any string that isn't convertable to an int, something that would be a compile time error otherwise. Additionally this pattern (overload+obsolete attribute) could be used even with the first "reified" class as a constructor but my point is that you don't need to reify the class (in fact its unhelpful). Instead you should understand that yes, generics should declare their types as specifically as possible and yes, there are refactoring patterns that exist so that you can compile your code relatively quickly after changing the type for a generic but it comes with the trade of turning compile time errors into runtime errors. Hope that helps.
If I have a class like this: -
static class Foo {
public static void Bar<T>(T item) { Console.WriteLine(item.ToString(); }
}
I know that in this example it's unnecessary to use T since all Types have ToString() on them etc. - it's simply a contrived example. What I'm more interested in is what happens under the bonnet in terms of the following: -
Foo.Bar("Hello");
Foo.Bar(123);
Foo.Bar(new Employee("Isaac"));
I broadly (think!) I understand reification i.e. if you make different types of a generic class e.g.
List<Int32>
List<String>
List<Employee>
etc. then at compile-time (or runtime?) we end up with three actual concrete types, one for each generic argument specified. Does the same apply to method calls in my first example i.e. would we still have a single class Foo but three reified Bar methods, one for String, Int32 and Employee?
This is where the difference between C++ templates and C# generics comes into play.
In C++, templates cause a new method to be generated for each type it is used with. In C#, however, the code in the method is only created once. The same code runs whether you call it with an int, string, or object type parameter.
Because C# generics remain generic when compiled, they can be exposed in compiled libraries without need for re-compilation. In C++, you are required to include the original template in your consuming code, so a new copy can be compiled.
Simply put, you only get one compiled method per generic method.
I have a situation where I would like to have objects of a certain type be able to be used as two different types. If one of the "base" types was an interface this wouldn't be an issue, but in my case it is preferable that they both be concrete types.
I am considering adding copies of the methods and properties of one of the base types to the derived type, and adding an implicit conversion from the derived type to that base type. Then users will be able treat the derived type as the base type by using the duplicated methods directly, by assigning it to a variable of the base type, or by passing it to a method that takes the base type.
It seems like this solution will fit my needs well, but am I missing anything? Is there a situation where this won't work, or where it is likely to add confusion instead of simplicity when using the API?
EDIT: More details about my specific scenario:
This is for a potential future redesign of the way indicators are written in RightEdge, which is an automated trading system development environment. Price data is represented as a series of bars, which have values for the open, low, high, and close prices for a given period (1 minute, 1 day, etc). Indicators perform calculations on series of data. An example of a simple indicator is the moving average indicator, which gives the moving average of the most recent n values of its input, where n is user-specified. The moving average might be applied to the bar close, or it could be applied to the output of another indicator to smooth it out.
Each time a new bar comes in, the indicators compute the new value for their output for that bar.
Most indicators have only one output series, but sometimes it is convenient to have more than one output (see MACD), and I want to support this.
So, indicators need to derive from a "Component" class which has the methods that are called when new data comes in. However, for indicators which have only one output series (and this is most of them), it would be good for them to act as a series themselves. That way, users can use SMA.Current for the current value of an SMA, instead of having to use SMA.Output.Current. Likewise, Indicator2.Input = Indicator1; is preferable to Indicator2.Input = Indicator1.Output;. This may not seem like much of a difference, but a lot of our target customers are not professional .NET developers so I want to make this as easy as possible.
My idea is to have an implicit conversion from the indicator to its output series for indicators that have only one output series.
You don't provide too many details, so here is an attempt to answering from what you provide.
Take a look at the basic differences:
When you have a base type B and a derived type D, an assignment like this:
B my_B_object = my_D_object;
assigns a reference to the same object. On the other hand, when B and D are independent types with an implicit conversion between them, the above assignment would create a copy of my_D_object and store it (or a reference to it if B is a class) on my_B_object.
In summary, with "real" inheritance works by reference (changes to a reference affect the object shared by many references), while custom type conversions generally work by value (that depends on how you implement it, but implementing something close to "by reference" behavior for converters would be nearly insane): each reference will point to its own object.
You say you don't want to use interfaces, but why? Using the combo interface + helper class + extension methods (C# 3.0 and .Net 3.5 or newer required) can get quite close to real multiple inheritance. Look at this:
interface MyType { ... }
static class MyTypeHelper {
public static void MyMethod(this MyType value) {...}
}
Doing that for each "base" type would allow you to provide default implementations for the methods you want to.
These won't behave as virtual methods out-of-the-box; but you may use reflection to achieve that; you would need to do the following from within the implementation on the Helper class:
retrieve a System.Type with value.GetType()
find if that type has a method matching the signature
if you find a matching method, invoke it and return (so the rest of the Helper's method is not run).
Finally, if you found no specific implementation, let the rest of the method run and work as a "base class implementation".
There you go: multiple inheritance in C#, with the only caveat of requiring some ugly code in the base classes that will support this, and some overhead due to reflection; but unless your application is working under heavy pressure this should do the trick.
So, once again, why you don't want to use interfaces? If the only reason is their inability to provide method implementations, the trick above solves it. If you have any other issue with interfaces, I might try to sort them out, but I'd have to know about them first ;)
Hope this helps.
[EDIT: Addition based on the comments]
I've added a bunch of details to the original question. I don't want to use interfaces because I want to prevent users from shooting themselves in the foot by implementing them incorrectly, or accidentally calling a method (ie NewBar) which they need to override if they want to implement an indicator, but which they should never need to call directly.
I've looked at your updated question, but the comment quite summarizes it. Maybe I'm missing something, but interfaces + extensions + reflection can solve everything multiple inheritance could, and fares far better than implicit conversions at the task:
Virtual method behavior (an implementation is provided, inheritors can override): include method on the helper (wrapped in the reflection "virtualization" described above), don't declare on the interface.
Abstract method behavior (no implementation provided, inheritors must implement): declare method on the interface, don't include it on the helper.
Non-virtual method behavior (an implementation is provided, inheritors may hide but can't override): Just implement it as normal on the helper.
Bonus: weird method (an implementation is provided, but inheritors must implement anyway; they may explicitly invoke the base implementation): that's not doable with normal or multiple inheritance, but I'm including it for completeness: that's what you'd get if you provide an implementation on the helper and also declare it on the interface. I'm not sure of how would that work (on the aspect of virtual vs. non-virtual) or what use it'd have, but hey, my solution has already beaten multiple inheritance :P
Note: On the case of the non-virtual method, you'd need to have the interface type as the "declared" type to ensure that the base implementation is used. That's exactly the same as when an inheritor hides a method.
I want to prevent users from shooting themselves in the foot by implementing them incorrectly
Seems that non-virtual (implemented only on the helper) will work best here.
or accidentally calling a method (ie NewBar) which they need to override if they want to implement an indicator
That's where abstract methods (or interfaces, which are a kind of super-abstract thing) shine most. The inheritor must implement the method, or the code won't even compile. On some cases virtual methods may do (if you have a generic base implementation but more specific implementations are reasonable).
but which they should never need to call directly
If a method (or any other member) is exposed to client code but shouldn't be called from client code, there is no programmatic solution to enforce that (actually, there is, bear with me). The right place to address that is on the documentation. Because you are documenting you API, aren't you? ;) Neither conversions nor multiple inheritance could help you here. However, reflection may help:
if(System.Reflection.Assembly.GetCallingAssembly()!=System.Reflection.Assembly.GetExecutingAssembly())
throw new Exception("Don't call me. Don't call me!. DON'T CALL ME!!!");
Of course, you may shorten that if you have a using System.Reflection; statement on your file. And, BTW, feel free to change the Exception's type and message to something more descriptive ;).
I see two issues:
User-defined type conversion operators are generally not very discoverable -- they don't show up in IntelliSense.
With an implicit user-defined type conversion operator, it's often not obvious when the operator is applied.
This doesn't been you shouldn't be defining type conversion operators at all, but you have to keep this in mind when designing your solution.
An easily discoverable, easily recognizable solution would be to define explicit conversion methods:
class Person { }
abstract class Student : Person
{
public abstract decimal Wage { get; }
}
abstract class Musician : Person
{
public abstract decimal Wage { get; }
}
class StudentMusician : Person
{
public decimal MusicianWage { get { return 10; } }
public decimal StudentWage { get { return 8; } }
public Musician AsMusician() { return new MusicianFacade(this); }
public Student AsStudent() { return new StudentFacade(this); }
}
Usage:
void PayMusician(Musician musician) { GiveMoney(musician, musician.Wage); }
void PayStudent(Student student) { GiveMoney(student, student.Wage); }
StudentMusician alice;
PayStudent(alice.AsStudent());
It doesn't sound as if your method would support a cross-cast. True multiple inheritance would.
An example from C++, which has multiple inheritance:
class A {};
class B {};
class C : public A, public B {};
C o;
B* pB = &o;
A* pA = dynamic_cast<A*>(pB); // with true MI, this succeeds
Then users will be able treat the derived type as the base type by using the duplicated methods directly, by assigning it to a variable of the base type, or by passing it to a method that takes the base type.
This will behave differently, however. In the case of inheritance, you're just passing your object. However, by implementing an implicit converter, you'll always be constructing a new object when the conversion takes place. This could be very unexpected, since it will behave quite differently in the two cases.
Personally, I'd make this a method that returns the new type, since it would make the actual implementation obvious to the end user.
Maybe I'm going too far off with this, but your use case sounds suspiciously as if it could heavily benefit from building on Rx (Rx in 15 Minutes).
Rx is a framework for working with objects that produce values. It allows such objects to be composed in a very expressive way and to transform, filter and aggregate such streams of produced values.
You say you have a bar:
class Bar
{
double Open { get; }
double Low { get; }
double High { get; }
double Close { get; }
}
A series is an object that produces bars:
class Series : IObservable<Bar>
{
// ...
}
A moving average indicator is an object that produces the average of the last count bars whenever a new bar is produced:
static class IndicatorExtensions
{
public static IObservable<double> MovingAverage(
this IObservable<Bar> source,
int count)
{
// ...
}
}
The usage would be as follows:
Series series = GetSeries();
series.MovingAverage(20).Subscribe(average =>
{
txtCurrentAverage.Text = average.ToString();
});
An indicator with multiple outputs is similar to GroupBy.
This might be a stupid idea, but: if your design requires multiple inheritance, then why don't you simply use a language with MI? There are several .NET languages which support multiple inheritance. Off the top of my head: Eiffel, Python, Ioke. There's probable more.
I've found loads of practical examples of this, and understand the practical output when overriding or hiding methods, but I'm looking for some under the covers info on why this is and why C# allows it when according to the rules of polymorphism, this shouldn't be allowed - at least, insofar as my understanding of polymorphism goes (which seems to coincide with the standard definitions found on Wikipedia/Webopedia).
Class Base
{
public virtual void PrintName()
{
Console.WriteLine("BaseClass");
}
}
Class FirstDerived : Base
{
public override void PrintName()
{
Console.WriteLine("FirstDerived");
}
}
Class SecondDerived : Base
{
public new void PrintName()
{
Console.WriteLine("SecondDerived");
}
}
Using the following code:
FirstDerived b = new FirstDerived();
BaseClass a = b;
b.PrintName();
a.PrintName();
I get:
FirstDerived
FirstDerived
Okay, I get that, makes sense.
SecondDerived c = new SecondDerived();
BaseClass a = c;
c.PrintName();
a.PrintName();
I get:
SecondDerived
BaseClass
Okay, that makes sense, too, instance a can't see c.PrintName() so it's using its own method to print its own name, however I can cast my instance to its true type using:
((SecondDerived)a).PrintName();
or
(a as SecondDerived).PrintName();
to get the output I would expect:
SecondDerived
So what is going on under the covers and what does this mean in terms of polymorphism? I'm told that this facility "breaks polymorphism" - and I guess according to the definition, it does. Is that right? Would an "object oriented" langage like C# really allow you to break one of the core principles of OOP?
(This answers the "why is it allowed" which I think is really the central point of your question. How it works in terms of the IL is less interesting to my mind... let me know if you want me to go into that though. Basically it's just a case of specifying the method to call with a different type token.)
It allows base classes to evolve without breaking derived classes.
Suppose Base didn't originally have the PrintName method. The only way to get at SecondDerived.PrintName would be to have an expression with a static type of SecondDerived, and call it on that. You ship your product, everything is fine.
Now fast forward to Base introducing a PrintName method. This may or may not have the same semantics of SecondDerived.PrintName - it's safest to assume that it doesn't.
Any callers of Base.PrintName know that they're calling the new method - they couldn't have called it before. Any callers which were previously using SecondDerived.PrintName still want to use it though - they don't want to suddenly end up calling Base.PrintName which could do something entirely different.
The difficulty is new callers of SecondDerived.PrintName, who may or may not appreciate that this isn't an override of Base.PrintName. They may be able to notice this from the documentation of course, but it may not be obvious. However, at least we haven't broken existing code.
When SecondDerived is recompiled though, the authors will be made aware that there's now a Base.PrintName class through a warning. They can either stick to their existing non-virtual scheme by adding the new modifier, or make it override the Base.PrintName method. Until they make that decision, they'll keep getting a warning.
Versioning and compatibility isn't usually mentioned in OO theory in my experience, but C# has been designed to try to avoid compatibility nightmares. It doesn't solve the problem completely, but it does a pretty good job.
I answer "how" it works. Jon has answered the "Why" part.
Calls to virtual methods are resolved a bit differently to those of non-virtual ones. Basically, a virtual method declaration introduces a "virtual method slot" in the base class. The slot will hold a pointer to the actual method definition (and the contents will point to an overridden version in the derived classes and no new slot will be created). When the compiler generates code for a virtual method call, it uses the callvirt IL instruction, specifying the method slot to call. The runtime will dispatch the call to the appropriate method. On the other hand, a non-virtual method is called with a call IL instruction, which will be statically resolved to the actual method by the compiler, at compile time (only with the knowledge of the compile-time type of the variable). new modifier does nothing in the compiled code. It essentially tells the C# compiler "Dude, shut up! I'm sure I'm doing the right thing" and turns off the compiler warning.
A new method (actually, any method without an override modifier) will introduce a completely separate chain of methods (new method slot). Note that a new method can be virtual itself. The compiler will look at the static type of the variable when it wants to resolve the method chain and the run time will choose the actual method in that specific chain.
According to the Wikipedia definition:
Type polymorphism in object-oriented
programming is the ability of one
type, A, to appear as and be used like
another type, B
Later on the same page:
Method overriding is where a subclass
replaces the implementation of one or
more of its parent's methods. Neither
method overloading nor method
overriding are by themselves
implementations of polymorphism.
The fact that SecondDerived does not provide an override for the PrintName does not affect its ability to appear and be used as Base. The new method implementation it provides will not be used anywhere an instance of SecondDerived is treated as an instance of the Base; it will be used only when that instance is explicitly used as an instance of SecondDerived.
Moreover, SecondClass can actually explicitly implement the Base.PrintName in addition to the new hiding implementation, thus providing its own override that will be used when treated as Base. (Though, Base has to be an explicit interface definition or has to derive from one to allow this)