Passing by reference: child of multiple interfaces

送分小仙女□ 提交于 2019-12-22 13:53:58

问题


I'm getting build errors when passing an object that implements multiple interface to a function that requires only 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:

  1. Why can't the Notifier be converted to a reference of type Sender, since it implements the Sender interface?
  2. Why is the argument to the constructor invalid?

Note: I'm transitioning from a C++, C and Java background to C#.


回答1:


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.




回答2:


You are misusing ref. In C#, only structs 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.



来源:https://stackoverflow.com/questions/5343936/passing-by-reference-child-of-multiple-interfaces

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!