Passing by reference: child of multiple interfaces
I'm getting build errors when passing an object that implements multiple interface to a function that requires only 开发者_JAVA技巧one of the interfaces.
I'm developing a communication package. The package has a Receiver class and a Sender Class. The Receiver class uses a notification interface Receive_Notifier (function object) for handling notifications. Likewise the Sender class uses a notification interface Send_Notifier to handling notifications.
interface Send_Notifier
{
void sending_text(string text);
}
interface Receive_Notifier
{
void raw_text_received(string raw_text);
}
class Sender
{
Send_Notifier m_notifier = null;
public Sender(ref Send_Notifier notifier)
{
m_notifier = notifier;
}
public void send(string text)
{
m_notifier.sending_text(text);
return;
}
}
class Receiver
{
Receive_Notifier m_notifier = null;
public Sender(ref Receive_Notifier notifier)
{
m_notifier = notifier;
}
public void receive(string text)
{
m_notifier.raw_text_received(text);
return;
}
}
I have combined the interfaces into a Communications_Notifier:
interface Communications_Notifier
: Send_Notifier, Receive_Notifier
{
}
I created a Notifier
class that implements the Communications_Notifier
interface:
class Notifier
: Communications_Notifier
{
public void sending_text(string text)
{
System.Console.WriteLine("--> " + text);
}
public void raw_text_received(string raw_text)
{
System.Console.WriteLine("<-- " + raw_text);
}
}
To simplify this post, I'll only show the sender class:
class Sender
{
Send_Notifier m_notifier = null;
public Sender(ref Send_Notifier notifier)
{
m_notifier = notifier;
}
public void send(string text)
{
m_notifier.sending_text(text);
return;
}
}
The issue is when I pass an instance of the Notifier
to an instance of the Sender
class:
class Program
{
static void Main(string[] args)
{
Notifier the_notifier = new Notifier();
Sender talker = new Sender(ref the_notifier); // ** Error generating line
talker.send("Hello\n");
string pause_text;
pause_text = System.Console.ReadLine();
}
}
The errors from Visual C# Express 2010:
Error 1 The best overloaded method match for 'Multiple_Inheritance_Interface.Sender.Sender(ref Multiple_Inheritance_Interface.Send_Notifier)' has some invalid arguments C:\Users\Thomas\Programming_Experiments\C_Sharp\Multiple_Inheritance_Interface\Multiple_Inheritance_Interface\Program.cs 55 29 Multiple_Inheritance_Interface
Error 2 Argument '1': cannot convert from 'ref Multiple_Inheritance_Interface.Notifier' to 'ref Multiple_Inheritance_Interface.Send_Notifier' C:\Users\Thomas\Programming_Experiments\C_Sharp\Multiple_Inheritance_Interface\Multiple_Inheritance_Interface\Program.cs 55 44 Multiple_Inheritance_Interface
Questions:
- Why can't the
Notifier
be converted to a reference of typeSender
, since it implements theSender
interface? - Why is the argument to the constructor invalid?
Note: I'm transitioning from a C++, C and Java background to C#.
ref
parameters support no co- or contra-variance. This is necessary since it can both read and change the reference. So if you passed in a derived class, and the function assigned a new instance that's not of that derived type your code would break.
Example:
void MakeCat(ref Animal animal)
{
animal=new Cat();
}
Dog dog=new Dog();
MakeCat(ref dog);
This obviously can't work since now you'd have a Cat
in your dog
variable.
I'm not sure why you're using ref
in the first place. With reference types you already can change the content of the instance passed in. You just can't replace the variable passed in with a new instance of that reference type.
out
parameters on the other hand look like they could be covariant. I suspect that they aren't is due to a limitation in the runtime: They are really ref
parameters marked with an attribute telling the compiler to treat it as an out
parameter.
You are misusing ref
. In C#, only struct
s are "passed by value" in a traditional sense. By default, object references are passed to methods. For example:
class HypotheticalSender
{
Send_Notifier m_notifier = null;
public HypotheticalSender(Send_Notifier notifier) // no "ref"
{
m_notifier = notifier;
}
}
// ...
HypotheticalSender talker = new HypotheticalSender(the_notifier);
the_notifier.InstanceProperty = "foobar";
// since talker's reference points to the same object, it sees "foobar" too
So there's no need at all for the ref
keyword in your constructor.
This is similar to Java's behavior, and dissimilar to C and C++'s behavior.
精彩评论