2013-03-05 173 views
0

问题:当我在父类中调用ValidateDynData时,程序流不会进入ValidateDynData的子类实现。无法获取父类调用子类方法 - 使用反射

我使用反射创建我的类的实例。当我从另一个项目中调用子类中的方法时,它会在子类中正确的方法(而不是父类的同名方法)中调用,所以看起来就像设置正确。

这就是反射一部分看起来像我的其他项目/类:

**注意2013年3月7日:我增加了更多的信息,以便你可以得到一般的感受这一点。它获取框的数量,通过框的数量循环,并为每个框创建一个控件并在表单中添加一个选项卡。这是CTool主要的Visual Studio项目,是项目中的一个类,它是一种形式。当我按表单上的按钮,与info(选择),在其子类中我将在稍后创建,它会以这种方法,CreatTabs():

 cb = new CB(); 
     int errValue = cb.FindUsbHid(ref HWndBoxID); //see how many boxes there are 
     if (errValue == 0 && HWndBoxID[0, 1] != 0) 
     { 
      for (int i = 0; i < cb.cbInfos.Length; i++) 
      { 

       if (controls[i] == null) 
       { 
        CB cb1 = new CB(); //need one for each box found or concurrent programming will fail 
        errValue = cb1.FindUsbHid(ref HWndBoxID); //need to do for each box to get all info 
        ///////////////////////////////////////// 
        if (errValue == 0) 
        { 
         _assembly = Assembly.LoadFrom(programDll); 
         _type = _assembly.GetType("CrWriter.PC"); 
         _objectInstance = Activator.CreateInstance(_type); 
         _parameters = new Object[] { cb1, programDll, templateArr, itsDll, cert, i, cb1.cbInfos[i].boxID }; 
         controls[i] = new Control(); 
         //The following lands in my child's GetPC method 
         //My parent also has a method called GetPC and that is called from the child. 
         //Then, most of the program flow is in the parent until I need to call ValidateDynData, 
         //discussed below 
         controls[i] = (Control)_type.InvokeMember("GetPC", BindingFlags.Default | BindingFlags.InvokeMethod, null, _objectInstance, _parameters); 

         controls[i].Dock = DockStyle.None; 
         this.Controls.Add(controls[i]); 
         TabPage newPage = new TabPage(string.Format("{0}:{1}", cb1.cbInfos[i].usbHandle, cb1.cbInfos[i].boxID)); 
         Console.WriteLine("frmUserForm::CreateTabs - Making new tab with cb.cbInfos[i].usbHandle:" + cb1.cbInfos[i].usbHandle + " and cb.cbInfos[i].boxID:" + cb1.cbInfos[i].boxID); 
         InitializeControls(controls[i]); 
         tabCtrlMain.Size = controls[i].Size; 
         tabCtrlMain.Width += 20; 
         tabCtrlMain.Height += 100; 
         this.Width = tabCtrlMain.Width + 20; 
         this.Height = tabCtrlMain.Height + 50; 
         newPage.Controls.Add(controls[i]); 
         tabCtrlMain.TabPages.Add(newPage); 
        } //no err for this cb 
       } //controls not null 
      } //for all cbInfo's 
      }//if no err in general finding out how many cb's 
      this.ResumeLayout(); 
      } 

由于我的GetPC的调用在孩子班而不是父母的情况下,它必须正确创建。所以我不确定为什么它没有登陆到正确的ValidateDynData方法中。也许我需要以某种方式将我的对象投射到程序D上。当我运行程序并检查_objectInstance时,它可能是一个问题: 变量................................. .................值

基:{GenericCrWriter.GenericPC} ...... CrWriter.PC

baseInst:...... .......................................... GenericCrWriter.GenericPC

但那么,_assembly指的是Ko/PC,而不是Generic/GenericPC。

此外,我的_assembly.GetType看起来不错。我的通用/父母没有任何名为CrWriter.PC

我想使用子类方法而不是父类为一些子类案件。出于某种原因,我得到父类方法,但它永远不会到达子类中的覆盖。任何想法为什么?我一直在提及Calling child class method from parent 但它没有得到孩子的方法。

在我的子类(KO)的PC.cs:

**注意2013年3月8日:PC.cs是在柯Visual Studio项目。 **这包含一个显示的表格 **注意3/7/2013:这是一个以孩子命名的单独的视觉工作室项目,我们称之为Ko。这里的重要课程是PC.cs.除了将数据传递给父项,提供自定义文本框和它们的名称之外,它不会做太多的工作,可以验证稍后以父项形式输入的数据。大部分流程都在父项中,否则。我添加了GetPC,setProgramName,setDTF方法。

public partial class PC : GenericPC 
    { 
     String childDllName = ""; //I just added this recently but it doesn't seem useful 
     GenericPC baseInst = new GenericPC(); 
     public Control GetPC(USB_Comm.CB cbInst, string dllSel, TemplateHApp.Templates.TEMPL[] templ, string dll, SC.SC.SITE c0, int slaveIndex, int BoxID) 
     { 
      childDllName = dll; 
      //call parent class methods 
      setProgramName(); 
      setDTF(); 
      ProcessDynData(); 
      return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID); 
     } 


     public void setProgramName() 
     { 
      Console.WriteLine("Ko did stuff"); 
      //Update label on form 
      var f = new F(); //F is a class in child class containing more info on it 
      string temp = f.GetProgramName(); 
      baseInst.setProgramName(temp); //this is displayed on parent's form 
     } 

     public void setDTF() 
     { 
      var f = new F(); 
      string temp = f.DTF(); 
      baseInst.setDTF(temp); //this is displayed on parent's form 
     } 

     private void ProcessDynamicData() 
     { 
      Console.WriteLine("Ko PC::ProcessDynamicData"); 
      Label lbl_dynData0 = new Label(); 
      Label lbl_dynData1 = new Label(); 
      lbl_dynData0.Text = "AT ."; 
      lbl_dynData1.Text = "VL ."; 
      lbl_dynData0.Location = new Point(57, 25); 
      lbl_dynData1.Location = new Point(57, 45); 
      Label[] lbl_dynData_Arr = new Label[4]; 
      lbl_dynData_Arr[0] = lbl_dynData0; 
      lbl_dynData_Arr[1] = lbl_dynData1; 
      TextBox tb_dynData0 = new TextBox(); 
      TextBox tb_dynData1 = new TextBox(); 
      tb_dynData0.Location = new Point(67, 25); 
      tb_dynData1.Location = new Point(67, 45); 
      tb_dynData0.Size = new Size(151,22); 
      tb_dynData1.Size = new Size(151, 22); 
      TextBox[] tb_dynData_Array = new TextBox[4]; 
      tb_dynData_Array[0] = tb_dynData0; 
      tb_dynData_Array[1] = tb_dynData1; 
      PC pc = this; //Tried adding this to get past problem but it's not turned out useful 
      //I think the way I access parent class from child is the problem of why flow in 
      //parent class isn't reaching overridden method in child when called: 
      baseInst.addDynamicDataTextBoxes(tb_dynData_Array, lbl_dynData_Arr, childDllName, pc); 
     } 

     public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result) 
     { //I added more info here, but it's probably too much info 3/7/2013 
      Console.WriteLine("Ko PC::ValidateDynData"); 
      result = -610; 
      //AT 
      if ((Convert.ToInt16(tb_dynData_Array[0].Text) >= 1) && (Convert.ToInt16(tb_dynData_Array[0].Text) <= 99)) 
       result = 0; 

      //VL 
      if (result == 0) 
      if ((Convert.ToInt16(tb_dynData_Array[1].Text) >= 69) && (Convert.ToInt16(tb_dynData_Array[1].Text) <= 100)) 
       result = 0; 
      else 
       result = -610; 
     } 

在我父类的GenericPC.cs:

**注意2013年3月8日:GenericPC是在通用的Visual Studio项目。 **注意3/7/2013当子类调用父类来初始化重要数据时,父类显示它是表单和字段(我认为简历布局显示它)。接下来,我们在表单上输入数据,包括Ko的定制数据,然后我们点击表单上的一个按钮(btn_Lock_Config_Click),它需要处理和验证它的数据。我添加了更多方法来获得流动的感觉。有一吨的父母比孩子(未显示),其中的try/catch更多的方法等

//base 
    public partial class GenericPC : UserControl 
    { 
    //class variables (wave your hands..too much info) 

    public Control GetPC(USB_Comm.CB cbInstance, string dllSelected, TemplateHApp.Templates.TEMPL[] template, string dll, SC.SC.SITE c0, int slaveIndex, int boxID) 
    { 
     cb = cbInstance; 
     SlaveIndex = slaveIndex; 
     createControls(); 
     itsDll = dll; 
     templateArr = template; 
     return this; //return the control for the control array 
    }  

    //called from child class 
    public void setProgramName(string name) 
    { 
     Console.WriteLine("Generic setProgramName slaveIndex:" + SlaveIndex); 
     lbl_Program_Name.Text = name; 
    } 

    //called from child class 
    public void setDTF(string theDTF) 
    { 
     Console.WriteLine("Generic setDTF slaveIndex:" + SlaveIndex); 
     lbl_Program_Name.Text += " "; 
     lbl_Program_Name.Text += theDTF; 
     lbl_Program_Name.Refresh(); 
    } 

    public void addDynamicDataTextBoxes(TextBox [] tb_dynData, Label [] lblTitle, String childName, Object child) 
    { 
     childHasDynamicData = true; //somebody's knocking 
     itsChildName = childName; //child name isn't turning out to be useful here 
     itsChild = child; //child isn't turning out to be useful here 
     Console.WriteLine("Generic addDynamicDataTextBoxes slaveIndex:" + SlaveIndex); 
     //Display what child wants 
     for (int i = 0; i < tb_dynData.Length; i++) 
     { 
      //assumes calling code knows real estate and planned for it 
      gb_dynamicData.Controls.Add(lblTitle[i]); 
      gb_dynamicData.Controls.Add(tb_dynData[i]); 
     } 
     itsEnteredDynamicData = tb_dynData; //nothing entered yet 
    } 

    private void btn_Lock_Config_Click(object sender, EventArgs e) 
    { 
     int status = 1; 
     Console.WriteLine("Generic btn_Lock slaveIndex:" + SlaveIndex); 
     //it does some flagging and data checking, etc. 
     status = processDynamicData(); 
    } 

    private int processDynData() 
    { 
     int returnCode = 0; //I'm setting it to desired value for example 
     //processes data, puts it into data arrays, etc, 
     if ((returnCode >= 0) && childHasDynamicData) 
      ValidateDynData(itsEnteredDynamicData, ref returnCode); 
      //start here for problem...it never calls child method, as intended 
    } 

    public virtual void ValidateDynData(TextBox[] tb_dynData_Array, ref int result) 
    { 
     Console.WriteLine("Generic::ValidateDynData passing off to child to validate special data"); 
    } 

任何想法,为什么它不会到子类实现ValidateDynData,当我打电话ValidateDynData在我父类?这是我的代码中的唯一区域,我试图让子类覆盖父实现,所以我不确定是否我做错了什么?

我检查了Generic.dll的正确版本,是在子项目/类中引用的。我在子类中做了一个干净的构建。任何其他应该检查的二进制文件?我的反射有什么问题吗? ValidateDynData的虚拟/覆盖使用有什么问题吗?

更新: 我一直在寻找更多的代码,并通过创建父/基类的实例来获得流入父类。所以我认为这就是为什么我没有进入在父类中调用时在子类中被覆盖的ValidateDynData。有没有另一种方法去父母的方法而不创建父母的实例?

GenericPC baseInst = new GenericPC(); 
    return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID); 

**更新13年3月7日: 也有可能的是,问题是,我按父母的窗体上的按钮,启动一个新线程,并通过这样做,不知道孩子类,所以这就是为什么当我调用ValidateDynData方法时流不会到达孩子的原因。

+0

请显示一个完整的例子,包括完整的类声明,项目/程序集之间的分配以及调用这些方法的完整代码。但是,请尽量缩小和缩小示例,不要包含与您的问题无关的代码。 – 2013-03-05 18:51:13

+1

不确定这是否相关,但编写的'processDynData()'不会编译,因为它需要一个返回的'int'。是否有可能运行较早的编译版本? – 2013-03-05 18:54:38

+1

我重新实现了这个(以简化的形式),它按预期工作(子电脑类被称为ValidateDynData)。简化为:1.消除部分类2.简化了GetPC和ValidateDynData的参数。没有其他任何东西可以工作,我仍然在猜测如上,你正在运行包含PC和GenericPC类的程序集的旧版本 – 2013-03-05 18:57:34

回答

1

简答:只需删除所有可怕的代码并重新开始。

较长的答案:

// (1) 
public partial class PC : GenericPC 
{ 
    // (2) 
    GenericPC baseInst = new GenericPC(); 

    public Control GetPC(…) 
    { 
     … 
     // (3) 
     return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID); 
    } 

    public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result) 
    { 
     // (4) 
     … 
    } 
} 

注释代码标线:

  1. 在这一点上,你声明PC作为后裔GenericPC。到现在为止还挺好。
  2. 在这里,您声明和实例的GenericPC具有无关与您正在使用的PC实例完全不同的实例。
  3. 你打电话GetPC,的PC一个实例,这又调用GetPC在于完全不同实例的GenericPC的方法;与原始PC实例没有任何共同之处!
  4. 最后,您希望控制流程结束最初的PC实例;但是实际上,当你实际上总是调用一些愚蠢的例子!

我的建议是阅读一本关于面向对象编程的书,它提供了C#中的示例。看起来你甚至错过了继承的观点,这是OOP的基本概念之一。


为了解决这个问题,就需要删除声明的baseInst,并更换到baseInst的方法与basekeyword所有呼叫。然后你的代码实际上会调用同一个实例中的祖先类别中声明的方法。大多数方法在GenericPC中应声明为virtual,并且您必须在PC中声明override

public partial class PC : GenericPC 
{ 
    public override Control GetPC(…) 
    { 
     … 
     return base.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID); 
    } 

    public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result) 
    { 
     … 
    } 
} 
+0

感谢您验证我所怀疑的事情......当我以为我曾经在使用孩子时遇到问题。我正在进一步研究它,即使我正在使用反射来调用子类,该子类也会引发一个属于父类的表单,当我按下表单上的按钮时,它实际上正在运行一个线程是父母而不是孩子。这是另一个问题。 – Michele 2013-03-09 21:07:27

+0

我正在计划重新设计它,并让反射直接调用父类,并在那里创建子类的实例。我要弄清楚如何在子类中创建一个控件并将其放在父类的表单中。所以,当有人在表单的孩子部分输入数据时,孩子的方法可以验证数据,而无需通过父母。即使在那时我必须经过父母去了解孩子的方法,我也会在那个时候有一个孩子的例子,并且访问起来会更容易。 – Michele 2013-03-09 21:08:09

+0

我意识到我遇到了设计和面向对象的问题。我拥有大量超过10年历史的C++代码的2000多年历史,我们一次又一次地使用现有设计......添加类似于其他电机等的电机。所以我可以理解为什么这是我的工作。 – Michele 2013-03-09 21:08:36