繁体   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