C# 如何创建一个类来创建另一个类的实例并访问所有者的私有成员

C# 如何创建一个类来创建另一个类的实例并访问所有者的私有成员,c#,class,inheritance,oop,C#,Class,Inheritance,Oop,我不确定我想做的事情是否违反了面向对象的准则,所以我会解释我在做什么,希望你们能给我一个更好的方法,如果我错了。我以前试过问这个问题,但我举了一个糟糕的例子,所以我认为这只会引起更多的混乱 所以我有一个主类,USBCommunicator。构造函数获取您想要与之对话的设备类型的产品ID。USBCommunicator类还有一个特定序列号的属性,可以与之通信。USBCommunicator具有OpenConnection和CloseConnection方法,可以打开或关闭数据流,以便在USB设备和

我不确定我想做的事情是否违反了面向对象的准则,所以我会解释我在做什么,希望你们能给我一个更好的方法,如果我错了。我以前试过问这个问题,但我举了一个糟糕的例子,所以我认为这只会引起更多的混乱

所以我有一个主类,USBCommunicator。构造函数获取您想要与之对话的设备类型的产品ID。USBCommunicator类还有一个特定序列号的属性,可以与之通信。USBCommunicator具有OpenConnection和CloseConnection方法,可以打开或关闭数据流,以便在USB设备和PC之间传输数据

要跨流发送数据,我希望USBCommunicator能够创建报表类的实例,设置一些参数,如超时、报表ID等,然后调用报表类的send()方法来实际发送数据。我认为除了USBCommunicator之外,任何类都不能创建Report类的实例。(例如,一个Boat类不应该能够创建CarDoor类的实例,因为Boat不能有车门。)最后,我最初认为Report类应该能够访问USBCommunicator的成员,但我猜这不是真的。如果USBCommunicator打开设备的流,则报告真正需要的只是传入一个参数,该参数是打开的流的引用/句柄。但是,该流应该是什么形式,以允许高级应用程序传递它呢?公共财产?这似乎不太正确

这就是我到目前为止所拥有的

namespace USBTools
{
    class HighLevelApplication
    {
        void main()
        {
            USBCommunicator myUSB = new USBCommunicator("15B3");
            myUSB.SerialNumber = "123ABC";
            myUSB.OpenConnection();
            myUSB.Report ReportToSend = new myUSB.Report(//how do I pass the stream here?);
                //It would be nice if I didn't have to pass in the stream because the stream shouldn't
                //be publicly available to the HighLevelApplication class right?
            ReportToSend.ReportID = 3;
            ReportToSend.Timeout = 1000;
            ReportToSend.Data = "Send this Data";
            ReportToSend.Send();
        }
    }

    class myUSB
    {
        myUSB(string PID)
        {
            //...
        }

        // public SerialNumber property

        // private stream field ???

        // public OpenConnection and CloseConnection methods

        class Report
        {
            Report(stream StreamToUse)
            {
                //...
            }
            Send()
            {
                //send the data
            }
        }
    }
}

您不显式访问私有成员,而是提供从报表类返回私有变量的公共属性

另外,只要您的报表类被标记为
public
,您就可以执行以下操作:

Report r = new Report();

在主USBCommunicator类中。但决不要将成员变量公开为公共变量,它们在报表中应该是私有的,但您应该包含公共属性来访问这些私有成员。

如果您不显式访问私有成员,则提供从报表类返回私有变量的公共属性

另外,只要您的报表类被标记为
public
,您就可以执行以下操作:

Report r = new Report();

在主USBCommunicator类中。但决不要将成员变量公开为公共变量,它们在报表中应该是私有的,但您应该包含公共属性来访问这些私有成员。

为什么不传递整个类(通过引用或复制)

myUSB.Report ReportToSend=new myUSB.Report(ParentClassWithStream)

myUSB.Report必须有私人成员才能保存引用


...
 class Report
        {
            ParentClassWithStream PC
            Report(ParentClassWithStream p)
            {
                PC = p

                //...
            }
            Send()
            {
                //send the data
            }
        }
...

你为什么不通过整个课程(通过参考或复制)

myUSB.Report ReportToSend=new myUSB.Report(ParentClassWithStream)

myUSB.Report必须有私人成员才能保存引用


...
 class Report
        {
            ParentClassWithStream PC
            Report(ParentClassWithStream p)
            {
                PC = p

                //...
            }
            Send()
            {
                //send the data
            }
        }
...

以下内容将满足您的要求。其思想是将报表类的接口与实际实现分离。它允许您创建一个只有USBCommunicator对象才能创建的实现类

public abstract class Report
{
   protected Report() { }

   public int ReportID {get; set;}
   public int Timeout {get; set;}
   public string Data {get; set; }
   public abstract void Send();
}

public class USBCommunicator 
{ 
    private Stream m_stream;

    public USBCommunicator (string PID) 
    { 
        //... 
    } 

    //Callers create new report objects via a method instead of directly using 'new'
    public Report CreateReport()
    {
        return new ReportImpl(m_stream);   
    }

    //Provides the implementation of the abstract methods of the Report class.
    private class ReportImpl : Report
    {
        private Stream m_stream;

        public ReportImpl(Stream stream)
        {
           m_stream = stream;
        }

        public void override Send()
        {
           //put implementation of Send here.
        }
    }
}
然后,您的高级应用程序将变成:

class HighLevelApplication        
{        
    void main()        
    {        
        USBCommunicator myUSB = new USBCommunicator("15B3");        
        myUSB.SerialNumber = "123ABC";        
        myUSB.OpenConnection();        

        Report reportToSend = myUSB.CreateReport();

        reportToSend.ReportID = 3;        
        reportToSend.Timeout = 1000;        
        reportToSend.Data = "Send this Data";        
        reportToSend.Send();
    }        
} 

以下内容将满足您的要求。其思想是将报表类的接口与实际实现分离。它允许您创建一个只有USBCommunicator对象才能创建的实现类

public abstract class Report
{
   protected Report() { }

   public int ReportID {get; set;}
   public int Timeout {get; set;}
   public string Data {get; set; }
   public abstract void Send();
}

public class USBCommunicator 
{ 
    private Stream m_stream;

    public USBCommunicator (string PID) 
    { 
        //... 
    } 

    //Callers create new report objects via a method instead of directly using 'new'
    public Report CreateReport()
    {
        return new ReportImpl(m_stream);   
    }

    //Provides the implementation of the abstract methods of the Report class.
    private class ReportImpl : Report
    {
        private Stream m_stream;

        public ReportImpl(Stream stream)
        {
           m_stream = stream;
        }

        public void override Send()
        {
           //put implementation of Send here.
        }
    }
}
然后,您的高级应用程序将变成:

class HighLevelApplication        
{        
    void main()        
    {        
        USBCommunicator myUSB = new USBCommunicator("15B3");        
        myUSB.SerialNumber = "123ABC";        
        myUSB.OpenConnection();        

        Report reportToSend = myUSB.CreateReport();

        reportToSend.ReportID = 3;        
        reportToSend.Timeout = 1000;        
        reportToSend.Data = "Send this Data";        
        reportToSend.Send();
    }        
} 

由于
USBCommunicator
管理所有重要资源(包括流的生存期),应用程序应该调用
USBCommunicator.Send
,而不是
Report.Send

public class USBCommunicator {
    public void Send(Report report) {

        // If it's appropriate, this method can also Open 
        // and Close the stream so callers don't have to.

        report.Send(this.stream);
    }
}
接下来,制作
Report.Send
internal,这样它就不是公共API的一部分,应用程序可以做到这一点:

public void main(string[] args) {
        USBCommunicator myUSB = new USBCommunicator("15B3");
        myUSB.SerialNumber = "123ABC";
        myUSB.OpenConnection();

        Report report = new Report(3, 1000, "Send this Data");
        myUSB.Send(report);
}

我不认为任何课程除了 USBCommunicator应该能够 创建报表的实例 班级

您当前的设计并没有阻止这一点——事实上,您的示例应用程序正在创建
报表
类的实例。如果确实要隐藏report类,则应将其设置为对
USBCommunicator
私有,并将其属性按如下方式推送到通信器的界面:

// USBCommunicator
public void Send(int reportID, int timeout, string data) {
    Report report = new Report(reportID, timeout, data);
    report.Send(this.stream);
}

由于
USBCommunicator
管理所有重要资源(包括流的生存期),应用程序应该调用
USBCommunicator.Send
,而不是
Report.Send

public class USBCommunicator {
    public void Send(Report report) {

        // If it's appropriate, this method can also Open 
        // and Close the stream so callers don't have to.

        report.Send(this.stream);
    }
}
接下来,制作
Report.Send
internal,这样它就不是公共API的一部分,应用程序可以做到这一点:

public void main(string[] args) {
        USBCommunicator myUSB = new USBCommunicator("15B3");
        myUSB.SerialNumber = "123ABC";
        myUSB.OpenConnection();

        Report report = new Report(3, 1000, "Send this Data");
        myUSB.Send(report);
}

我不认为任何课程除了 USBCommunicator应该能够 创建报表的实例 班级

您当前的设计并没有阻止这一点——事实上,您的示例应用程序正在创建
报表
类的实例。如果确实要隐藏report类,则应将其设置为对
USBCommunicator
私有,并将其属性按如下方式推送到通信器的界面:

// USBCommunicator
public void Send(int reportID, int timeout, string data) {
    Report report = new Report(reportID, timeout, data);
    report.Send(this.stream);
}

这不是违反了面向对象的准则吗?如果父类尊重封装,那么就不是了,因为您将使用访问方法来获取所需的信息。这只是一个类引用了另一个类,这不是违反了面向对象的指导原则吗?如果您的父类尊重封装,那么就不是了,因为您将使用访问方法来获取所需的信息。它只是一个引用另一个类的类,那么我的report类位于何处,是什么阻止HighLevelApplication执行此reportToSend=new report()?这将是不好的,因为它没有流,对吗?报表是抽象的,没有实现Send,因此在继承报表并在其他地方实现Send之前,您将无法对其执行任何操作。那么我的报表类位于何处?是什么阻止HighLevelApplication执行此报表报表