如何从另一个类的静态方法调用实例方法(即只有一个对象)?

时间:2010-01-15 09:15:03

标签: c# oop formatting

我的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对象?

谢谢,如果您需要更多信息,请告诉我们!

4 个答案:

答案 0 :(得分:3)

您有两个设计问题:

如何从静态方法调用实例方法

  

因为HookCallBack方法是   static,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 / reset方法,如果静态表单引用了其他对象,那么你的app会慢慢泄漏内存,{{3 }}。我实际上推荐这样的东西:

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

因此,您的FormFactory控制表单的生命周期,现在您可以使用new FormFactory.GetForm1()获取Form1的现有或新实例。

答案 1 :(得分:2)

将按键传递给其他表格

在我看来,你基本上只是将按键传递给你的表单,这意味着一种基本的消息通知/观察者模式。也许你只需要一个更好的设计模式。请尝试以下方法:

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
    }
}

请记住,必须在表单关闭时取消挂起表单事件处理程序,否则表单不会被垃圾收集,并且您将遇到许多奇怪的问题,在非可见表单上引发事件

答案 2 :(得分:1)

根据你所写的内容,我认为这样可行:

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
}

答案 3 :(得分:1)

我认为类似于Form1类:

private static Form1 instance;


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

在您使用它们的课程中:

Form1 form1 = Form1.Instance;

将完成这项工作。这将首先检查是否有一个,如果是,它将返回实例,否则它将创建一个,下次它将返回一个。