无法调用Window类及空引用异常问题求助
问题分析
你遇到的几个错误根源清晰明了:
- System.NullReferenceException:Application类中
private Window window;仅声明了字段但未初始化,调用window.CreateWindow()时window为null,自然触发空引用异常。 - CS0144:Window是抽象类,C#语法明确禁止直接实例化抽象类或接口。
- CS0120:静态方法
CreateWindow中调用了非静态的抽象方法Create(),静态方法属于类本身,无法访问仅属于实例的成员。
解决方案
我们通过重构窗口创建逻辑,利用工厂模式正确实例化WindowsWindow子类,同时修复Application中的空引用问题:
1. 修改Window抽象类,实现静态工厂方法
把抽象的实例Create方法改为静态工厂方法,解决"要创建对象但需要先有对象调用方法"的矛盾:
using System; namespace Jade { public struct WindowProps { public string Title; public uint Width; public uint Height; public WindowProps(in string title = "Camellia Engine", uint width = 1280, uint height = 720) { Title = title; Width = width; Height = height; } } public abstract class Window { public delegate void EventCallbackFn(Event e); ~Window() { } public abstract void OnUpdate(); public abstract uint GetWidth(); public abstract uint GetHeight(); public abstract void SetEventCallback(in EventCallbackFn callback); public abstract void SetVSync(bool enabled = false); public abstract bool IsVSyncEnabled(); // 静态工厂方法,直接返回具体平台窗口实例(可扩展多平台判断) public static Window Create(WindowProps props = new WindowProps()) { // 这里可添加平台分支判断,比如Windows/macOS/Linux return new WindowsWindow(props); } } }
2. 调整WindowsWindow类,移除冗余重写
父类的Create改为静态后,子类无需再重写抽象的Create方法,同时修复GCHandle的生命周期问题:
using System; using GLFW; using GLFW.Game; using System.Runtime.InteropServices; namespace Jade { // 若需跨命名空间访问,将internal改为public public class WindowsWindow : Window { public static bool m_isGLFWInitialized = false; private NativeWindow m_window; private WindowData m_Data; private GCHandle m_dataHandle; // 保存GCHandle,避免指针失效 public WindowsWindow(WindowProps props) { Init(props); } ~WindowsWindow() { Shutdown(); } public override void OnUpdate() { Glfw.PollEvents(); Glfw.SwapBuffers(m_window); } public override uint GetWidth() { return m_Data.Width; } public override uint GetHeight() { return m_Data.Height; } public override void SetEventCallback(in EventCallbackFn callback) { m_Data.EventCallback = callback; } public override void SetVSync(bool enabled) { Glfw.SwapInterval(enabled ? 1 : 0); m_Data.VSync = enabled; } public override bool IsVSyncEnabled() { return m_Data.VSync; } private void Init(in WindowProps props) { m_Data.Title = props.Title; m_Data.Width = props.Width; m_Data.Height = props.Height; Log.CM_CORE_INFO($"Creating window: {props.Title} ({props.Width}x{props.Height})"); if (!m_isGLFWInitialized) { bool success = Glfw.Init(); m_isGLFWInitialized = true; } m_window = new GameWindow((int)props.Width, (int)props.Height, m_Data.Title); // 固定WindowData内存,直到窗口销毁 m_dataHandle = GCHandle.Alloc(m_Data, GCHandleType.Pinned); IntPtr dataPtr = m_dataHandle.AddrOfPinnedObject(); Glfw.MakeContextCurrent(m_window); Glfw.SetWindowUserPointer(m_window, dataPtr); SetVSync(true); } public void Shutdown() { Glfw.DestroyWindow(m_window); // 释放固定的内存 if (m_dataHandle.IsAllocated) m_dataHandle.Free(); if (m_isGLFWInitialized) { Glfw.Terminate(); m_isGLFWInitialized = false; } } private struct WindowData { public string Title; public uint Width, Height; public bool VSync; public EventCallbackFn EventCallback; }; } }
3. 修复Application类的空引用问题
在Application构造函数中,通过Window的静态工厂方法初始化window字段:
namespace Jade { public class Application { private bool m_Running = true; private Window window; public Application() { // 通过静态工厂方法创建窗口实例 window = Window.Create(); } ~Application() { // 销毁窗口资源 if (window is WindowsWindow windowsWindow) { windowsWindow.Shutdown(); } } public void Run() { while (m_Running) { window.OnUpdate(); } } public Application CreateApplication() { return new Sandbox(); } } }
额外提示
- 若需多平台支持,可在
Window.Create()中加入平台判断逻辑(比如使用OperatingSystem.IsWindows()等API),返回对应平台的窗口子类。 - 确保Sandbox类(若继承自Application)的构造逻辑不会覆盖window的初始化流程。
内容的提问来源于stack exchange,提问作者Bobi
相关产品推荐
相关产品推荐

