0

問題: 親クラスで ValidateDynData を呼び出すと、プログラム フローが ValidateDynData の子クラスの実装に進みません。

リフレクションを使用してクラスのインスタンスを作成します。別のプロジェクトから子クラスのメソッドを呼び出すと、(親の同名メソッドではなく) 子クラスの正しいメソッドになるため、正しく設定されているようです。

これは、私の他のプロジェクト/クラスで反射部分がどのように見えるかです:

**注 2013 年 3 月 7 日: 一般的な雰囲気をつかんでいただけるように、さらに情報を追加しました。ボックスの数を取得し、ボックスの数をループして、ボックスごとにコントロールを作成し、フォームにタブを追加します。これはメインの CTool ビジュアル スタジオ プロジェクトであり、フォームであるプロジェクト内のクラスです。フォームのボタンを押すと、後で作成する子クラスの情報 (選択済み) が表示され、このメソッド 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 メソッドに到達しない理由がわかりません。どうにかしてオブジェクトを programDll にキャストする必要があるかもしれません。プログラムを実行して _objectInstance を検査すると、問題が発生する可能性があります: variable................................. ................価値

ベース: {GenericCrWriter.GenericPC} ......CrWriter.PC

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

しかし、_assembly は Generic/GenericPC ではなく Ko/PC を参照しています。

また、私の _assembly.GetType も良さそうです。私のジェネリック/親には CrWriter.PC という名前のものがありません

一部の子クラスのケースでは、親クラスの代わりに子クラス メソッドを使用しようとしています。なぜか親クラスのメソッドまでた​​どり着くのですが、子のオーバーライドまでたどり着けません。理由はありますか?親から子クラスのメソッドを呼び出すについて言及してきましたが 、子のメソッドに到達していません。

子クラス (Ko) の私の PC.cs で:

**2013 年 3 月 8 日: PC.cs は Ko Visual Studio プロジェクトにあります。**これには表示されるフォームが含まれます **注 2013 年 3 月 7 日: これは子にちなんで名付けられた別のビジュアル スタジオ プロジェクトです。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 は Generic Visual Studio プロジェクトにあります。**注意 2013 年 3 月 7 日 子クラスが親クラスを呼び出して重要なデータを初期化すると、親クラスはそのフォームとフィールドを表示します (レジューム レイアウトに表示されると思います)。次に、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); 

**2013 年 3 月 7 日更新: 問題は、新しいスレッドを開始する親フォームのボタンを押すことである可能性もあります。これにより、子クラスについて認識されないため、フローが機能しません。 ValidateDynData メソッドを呼び出すと、子が取得されません。

4

1 に答える 1

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. ここでは、作業中のインスタンスとは何の関係もない完全に異なるインスタンスを宣言してインスタンス化しますGenericPCPC
  3. GetPCのインスタンスのメソッドである を呼び出します。これは、完全に異なる のインスタンスPC呼び出します。元のインスタンスとの共通点はありません!GetPCGenericPCPC
  4. 最後に、制御フローが元のPCインスタンスで終了することを期待します。しかし、事実上、ばかげたインスタンスのメソッドを常に呼び出している場合は、決して起こりませんGenericPC!

私のお勧めは、C# でサンプルを提供するオブジェクト指向プログラミングに関する本を読むことです。OOP の基本概念の 1 つである継承のポイントさえ見逃しているようです。


これを修正するには、 の宣言を削除し、のメソッドへのすべての呼び出しをキーワードbaseInstに置き換える必要があります。次に、コードは実際に同じインスタンス内の祖先クラスで宣言されたメソッドを呼び出します。また、ほとんどのメソッドは のように宣言する必要があり、 でそれらを宣言する必要があります。baseInstbase virtualGenericPCoverridePC

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)
    {
        …
    }
}
于 2013-03-08T18:42:00.227 に答える