簡體   English   中英

如何從另一個類的靜態方法(即只有一個對象)調用實例方法?

[英]How do I call an instance method from another classes' static method (i.e. have only one object)?

我的form1類包含一堆需要保存的數據,因此一次只能運行一個實例。

public partial class Form1 : Form
{
    public string form1string = "I really need to save this data";

    public Form1()
    {
        InitializeComponent();


        // Even if I pass my form1 object here I still can't access it from
        // the upcoming static methods.
        InterceptKeys hook = new InterceptKeys();
    }

InterceptKeys(不是我的代碼)包含鍵盤鈎子所需的一堆靜態方法。

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
    {
       int trueKeyPressed = Marshal.ReadInt32(lParam);

       if (Form1.mirror)
       {
           Form1.newKeyPress(trueKeyPressed);
           return (IntPtr)1;
       }
    }
    return CallNextHookEx(_hookID, nCode, wParam, lParam);
 }

因為HookCallBack方法是靜態的,所以Form1.newKeyPress()也需要是靜態的。

但是,如果newKeyPress處於靜態狀態,則無法訪問所需的數據! 我不想在這里聲明一個新的form1對象,因為那樣會給我不同版本的數據。 正確?

我不是面向對象的專家。 我應該如何格式化它,以確保所有InterceptKey的form1方法調用都轉到我想要的form1對象?

謝謝,如果需要更多信息,請告訴我!

您有兩個設計問題:

如何從靜態方法調用實例方法

因為HookCallBack方法是靜態的,所以Form1.newKeyPress()也需要是靜態的。

您可以將主窗體的實例傳遞給HookCallBack方法,只需向靜態方法添加一個附加參數即可:

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam, Form1 form)
{
   // ...
}

這實際上是首選策略。 無論您的方法和類對其他對象有依賴關系,都應將依賴關系傳遞給方法,而不要從全局狀態中拉出它們。

除非如此,否則您可以遍歷Application.OpenForms集合並找到您要查找的表單,如下所示:

var form = Application.OpenForms.OfType<Form1>().First();
form.newKeyPress();

如何一次打開一個表單實例

其他人建議將您的表單靜態化-這是一種方法,但這是一種不好的方法。 靜態形式沒有得到收集垃圾的處置時,你必須實現自己的init /復位的方法,當你顯示/隱藏表單,如果靜態形式有那么你的應用程序會慢慢泄漏內存到其他對象的引用, 除其他事項外 我實際上建議這樣的事情:

class FormFactory
{
    public Form1 GetForm1()
    {
        return Application.OpenForms.OfType<Form1>().FirstOrDefault ?? new Form1();
    }
}

因此,FormFactory控制着表單的生命周期,現在您可以使用new FormFactory.GetForm1()獲得Form1的現有實例或新實例。

將按鍵傳遞給其他形式

在我看來,您基本上只是將按鍵傳遞給表單,這意味着一種基本的消息通知/觀察者模式。 也許您只需要一個更好的設計模式。 請嘗試以下操作:

public class MessageHooks
{
    public static event Action<int> OnHookCallback;

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            int trueKeyPressed = Marshal.ReadInt32(lParam);
            if (OnHookCallBack != null)
            {
                OnHookCallback(trueKeyPressed);
            }
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }
}

你猜怎么了? 現在,您的HookCallBack方法甚至不需要知道表單的存在。 相反,您的表單將自己注冊到事件處理程序中,如下所示:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        MessageHooks.OnHookCallBack += MessageHooks_OnHookCallBack;
        this.FormClosed += (sender, e) => MessageHooks.OnHookCallBack -= MessageHooks_OnHookCallBack; // <--- ALWAYS UNHOOK ON FORM CLOSE
    }

    void MessageHooks_OnHookCallBack(int keyPressed)
    {
        // do something with the keypress
    }
}

請記住,您必須在窗體關閉時解開窗體事件處理程序,否則窗體將不會被垃圾收集,並且您會遇到很多奇怪的問題,從而在不可見的窗體上引發事件。

從您寫的內容來看,我認為這將起作用:

Form1 ,具有一個Form1類型的靜態成員,該成員將保存實例:

private static Form1 instance;

Form1構造函數中,將此靜態成員設置為正在創建的實例:

public Form1()
{
    // Existing code

    Form1.instance = this;
}

現在,將newKeyPress靜態,並使用靜態成員查找實際的表單實例:

public static void newKeyPress(int trueKeyPressed)
{
    Form1 thisIsTheForm1Instance = Form1.instance;

    // Now instance.form1string is the data you want
}

我認為就像在Form1類中一樣:

private static Form1 instance;


 public static Form1 Instance
 {
      get
      {
          if (instance == null)
          {
              instance = new Form1();
          }
          return instance;
      }
 }

在使用它們的類中:

Form1 form1 = Form1.Instance;

會做的工作。 這將首先檢查是否存在一個,如果是,它將返回該實例,否則將創建一個,然后再次返回一個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM