静态变量在方法调用中为空,但在程序中已初始化
Static Variable Null In Method Call, But Initialized In Program
我有点头疼,不知道是否有人知道答案。
设置基本上是这样的:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
让我抓狂的问题是 StaticClass.StaticVariable 在 IXmlSerializable.ReadXml() 方法中为 null,即使它是在变量设置后立即调用的。
值得注意的是,断点未命中,Debugger.Launch() 在发生问题的确切位置被忽略。
奇怪的是,我通过引发异常确定 AppDomain.CurrentDomain.FriendlyName 属性 对于填充静态变量的位置与空值相同!
为什么静态变量超出范围?!?这是怎么回事?!?如何共享我的变量?
编辑:
我根据回复中的建议添加了一个静态构造函数,并让它执行 Debug.WriteLine。我注意到它被调用了两次,尽管所有代码在同一个 AppDomain 中似乎都是 运行。这是我在输出 window 中看到的内容,我希望这是一个有用的线索:
静态构造函数调用时间:2015-01-26T13:18:03.2852782-07:00
...已加载 'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
...已加载 'Microsoft.GeneratedCode'...
...已加载 'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'...
...已加载 'C:\USERS...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO.0EXP\EXTENSIONS...SharePointAdapter.dll'。已加载符号。
...已加载 'Microsoft.GeneratedCode'。
静态构造函数调用时间:2015-01-26T13:18:03.5196524-07:00
其他详细信息:
这是实际代码,因为一些评论者认为它可能有所帮助:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
bstrArg = "\"" + paramPath + "\"",
bstrExe = EmulatorPath,
LaunchFlags = grfLaunch | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_WaitForAttachComplete,
dwDebugEngineCount = 0,
guidLaunchDebugEngine = VSConstants.CLSID_ComPlusOnlyDebugEngine,
};
var debugger = Project.GetService(typeof(SVsShellDebugger)) as IVsDebugger4;
var targets = new[] { testDebugInfo };
var processInfos = new[] { new VsDebugTargetProcessInfo() };
debugger.LaunchDebugTargets4(1, targets, processInfos);
//this is in the emulator program that spins up
public partial class App : Application
{
//***NOTE***: static constructors added to static classes.
//Problem still occurs and output is as follows (with some load messages in between):
//
//MefInitializer static constructor called at: 2015-01-26T15:34:19.8696427-07:00
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.0609845-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.3399330-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
protected override void OnStartup(StartupEventArgs e)
{
//...
//initializes a MEF container singleton (stored as static variable)
MefInitilizer.Run();
//here's where it blows up. the important details are that
//FullSelection implements IXmlSerializable, and its implemention
//ends up referencing the MEF container singleton, which ends up
//null, even though it was initialized in the previous line.
//NOTE: the approach works perfectly under a different context
//so the problem is not the code itself, per se, but a problem
//with the code in the environment it's running in.
var systems = XmlSerialization.FromXml<List<FullSelection>>(systemsXml);
}
}
public static class MefInitilizer
{
static MefInitilizer() { Debug.WriteLine("MefInitializer static constructor called at: " + DateTime.Now.ToString("o")); }
public static void Run()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
var container = new CompositionContainer(catalog);
ContainerSingleton.Initialize(container);
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
Debug.WriteLine("ContainerSingleton static constructor called at: " + DateTime.Now.ToString("o") + ". Type: " + typeof(ContainerSingleton).AssemblyQualifiedName);
}
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
}
尝试向 ContainerSingleton
添加静态构造函数。我相信这是BeforeFieldInit再次抬起丑陋的头。
请记住,我刚刚复制了您的代码以尝试重现您的问题。
当 运行 此代码时,我在 Debug.Write 上收到 NullReferenceException,AnotherClass 在调用解决之前未正确初始化。
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
但是,当我将静态构造函数添加到所有 类 静态字段时,它按预期工作:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
static MefInitilizer()
{
}
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
}
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
我会说这肯定是 BeforeFieldInit 问题。
据我了解,您的代码是 Visual Studio 的插件,您的应用程序的主要问题是您的 class 被实例化两次,一次用于普通 AppDomain
,还有一次因为其他原因你无法真正找到。
首先,我在这里看到一个来自 Visual studio 的潜在 sandboxing
- 它想要测试您的代码的各种权利集,以确保您的代码不会损害任何其他部分Visual Studio 或最终用户工作。在这种情况下,您的代码可能会被加载到另一个 AppDomain 中,但没有一些权限(您可以找到一个 good article at the MSDN),因此您可以理解为什么每个应用程序调用您的代码两次。
其次,我想指出你误解了静态constructor
和静态method
的概念:
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
与
不一样
public static ContainerSingleton()
{
compositionContainer = container;
}
因此,我建议您将所有初始化逻辑移动到静态容器中,如下所示:
public class ContainerSingleton
{
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static ContainerSingleton()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
compositionContainer = new CompositionContainer(catalog);
}
}
第二种方法:我想指出你用于获取单例的模式已经过时,尝试使用 Lazy<T>
class,像这样:
public class ContainerSingleton
{
private static Lazy<CompositionContainer> compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
return compositionContainer.Value;
}
}
public static ContainerSingleton()
{
compositionContainer = new Lazy<CompositionContainer>(() => Initialize());
}
public static void Initialize()
{
// Full initialization logic here
}
}
此外,您应该记住,仅添加空的静态构造函数是不够的 - 您应该将所有赋值移动到它,因此您应该替换这样的代码:
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
这个:
public class AnotherClass
{
static AnotherClass()
{
Test = ContainerSingleton.ContainerInstance;
}
public static String Test;
}
更新:
@Colin 您甚至可以使用 [LazyTask
type][https://msdn.microsoft.com/en-us/magazine/dn683795.aspx] - simply pass a Func
to your constructor, and it will be a thread-safe approach, see more in the article. The same Id
of the AppDomain
means nothing - the sandbox could run your code via AppDomain.ExecuteAssembly
方法(它在 4.5 中已过时,但仍然可能是一种可能的变体)来查看它在各种权限集下的行为.
可能在 .NET 4.5 中有另一种技术,但现在找不到相关文章。
更新二:
正如我在您的代码中看到的,您正在从磁盘读取一些信息。尝试为此添加 Code Access Security 规则以查看您的代码是否 运行 受限权限,如下所示:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\example\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
有关 FileIOPermission
Class 的更多信息,请参见 MSDN。
感谢所有提出建议的人!我从来没有弄清楚到底发生了什么(如果我知道的话,我会继续 investigate/post 更新),但我最终想出了一个解决方法。
一些人建议将静态 class 的初始化内部化,但由于实际问题的性质,初始化逻辑必须外部化(我基本上是加载一个 DI/service 位置容器其成分因环境而异)。
此外,我怀疑它不会有帮助,因为我可以观察到静态构造函数被调用了两次(因此,无论有什么初始化逻辑都只会被调用两次,这并没有直接解决问题) .
不过,这个建议让我走上了正轨。
在我的例子中,我加载的 none 服务需要是有状态的,所以除了性能影响之外,初始化发生两次并不重要。
因此,我只是让静态 class 检查 MEF 容器是否已加载,如果未加载,我将读取指定 class 处理初始化的配置文件。
通过这样做,我仍然可以根据环境改变 MEF 容器的组成,目前工作得很好,即使它不是 理想 解决方案。
我想把赏金分给所有提供帮助的人,但由于这似乎不可能,我可能会奖励 OakNinja,因为他是一个英雄,能够提出尽可能多的好点子鉴于我提供的信息,这是预期的。再次感谢!
我有点头疼,不知道是否有人知道答案。
设置基本上是这样的:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
让我抓狂的问题是 StaticClass.StaticVariable 在 IXmlSerializable.ReadXml() 方法中为 null,即使它是在变量设置后立即调用的。
值得注意的是,断点未命中,Debugger.Launch() 在发生问题的确切位置被忽略。
奇怪的是,我通过引发异常确定 AppDomain.CurrentDomain.FriendlyName 属性 对于填充静态变量的位置与空值相同!
为什么静态变量超出范围?!?这是怎么回事?!?如何共享我的变量?
编辑:
我根据回复中的建议添加了一个静态构造函数,并让它执行 Debug.WriteLine。我注意到它被调用了两次,尽管所有代码在同一个 AppDomain 中似乎都是 运行。这是我在输出 window 中看到的内容,我希望这是一个有用的线索:
静态构造函数调用时间:2015-01-26T13:18:03.2852782-07:00
...已加载 'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
...已加载 'Microsoft.GeneratedCode'...
...已加载 'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'...
...已加载 'C:\USERS...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO.0EXP\EXTENSIONS...SharePointAdapter.dll'。已加载符号。
...已加载 'Microsoft.GeneratedCode'。
静态构造函数调用时间:2015-01-26T13:18:03.5196524-07:00
其他详细信息:
这是实际代码,因为一些评论者认为它可能有所帮助:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
bstrArg = "\"" + paramPath + "\"",
bstrExe = EmulatorPath,
LaunchFlags = grfLaunch | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_WaitForAttachComplete,
dwDebugEngineCount = 0,
guidLaunchDebugEngine = VSConstants.CLSID_ComPlusOnlyDebugEngine,
};
var debugger = Project.GetService(typeof(SVsShellDebugger)) as IVsDebugger4;
var targets = new[] { testDebugInfo };
var processInfos = new[] { new VsDebugTargetProcessInfo() };
debugger.LaunchDebugTargets4(1, targets, processInfos);
//this is in the emulator program that spins up
public partial class App : Application
{
//***NOTE***: static constructors added to static classes.
//Problem still occurs and output is as follows (with some load messages in between):
//
//MefInitializer static constructor called at: 2015-01-26T15:34:19.8696427-07:00
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.0609845-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.3399330-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
protected override void OnStartup(StartupEventArgs e)
{
//...
//initializes a MEF container singleton (stored as static variable)
MefInitilizer.Run();
//here's where it blows up. the important details are that
//FullSelection implements IXmlSerializable, and its implemention
//ends up referencing the MEF container singleton, which ends up
//null, even though it was initialized in the previous line.
//NOTE: the approach works perfectly under a different context
//so the problem is not the code itself, per se, but a problem
//with the code in the environment it's running in.
var systems = XmlSerialization.FromXml<List<FullSelection>>(systemsXml);
}
}
public static class MefInitilizer
{
static MefInitilizer() { Debug.WriteLine("MefInitializer static constructor called at: " + DateTime.Now.ToString("o")); }
public static void Run()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
var container = new CompositionContainer(catalog);
ContainerSingleton.Initialize(container);
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
Debug.WriteLine("ContainerSingleton static constructor called at: " + DateTime.Now.ToString("o") + ". Type: " + typeof(ContainerSingleton).AssemblyQualifiedName);
}
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
}
尝试向 ContainerSingleton
添加静态构造函数。我相信这是BeforeFieldInit再次抬起丑陋的头。
请记住,我刚刚复制了您的代码以尝试重现您的问题。 当 运行 此代码时,我在 Debug.Write 上收到 NullReferenceException,AnotherClass 在调用解决之前未正确初始化。
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
但是,当我将静态构造函数添加到所有 类 静态字段时,它按预期工作:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
static MefInitilizer()
{
}
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
}
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
我会说这肯定是 BeforeFieldInit 问题。
据我了解,您的代码是 Visual Studio 的插件,您的应用程序的主要问题是您的 class 被实例化两次,一次用于普通 AppDomain
,还有一次因为其他原因你无法真正找到。
首先,我在这里看到一个来自 Visual studio 的潜在 sandboxing
- 它想要测试您的代码的各种权利集,以确保您的代码不会损害任何其他部分Visual Studio 或最终用户工作。在这种情况下,您的代码可能会被加载到另一个 AppDomain 中,但没有一些权限(您可以找到一个 good article at the MSDN),因此您可以理解为什么每个应用程序调用您的代码两次。
其次,我想指出你误解了静态constructor
和静态method
的概念:
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
与
不一样public static ContainerSingleton()
{
compositionContainer = container;
}
因此,我建议您将所有初始化逻辑移动到静态容器中,如下所示:
public class ContainerSingleton
{
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static ContainerSingleton()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
compositionContainer = new CompositionContainer(catalog);
}
}
第二种方法:我想指出你用于获取单例的模式已经过时,尝试使用 Lazy<T>
class,像这样:
public class ContainerSingleton
{
private static Lazy<CompositionContainer> compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
return compositionContainer.Value;
}
}
public static ContainerSingleton()
{
compositionContainer = new Lazy<CompositionContainer>(() => Initialize());
}
public static void Initialize()
{
// Full initialization logic here
}
}
此外,您应该记住,仅添加空的静态构造函数是不够的 - 您应该将所有赋值移动到它,因此您应该替换这样的代码:
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
这个:
public class AnotherClass
{
static AnotherClass()
{
Test = ContainerSingleton.ContainerInstance;
}
public static String Test;
}
更新:
@Colin 您甚至可以使用 [LazyTask
type][https://msdn.microsoft.com/en-us/magazine/dn683795.aspx] - simply pass a Func
to your constructor, and it will be a thread-safe approach, see more in the article. The same Id
of the AppDomain
means nothing - the sandbox could run your code via AppDomain.ExecuteAssembly
方法(它在 4.5 中已过时,但仍然可能是一种可能的变体)来查看它在各种权限集下的行为.
可能在 .NET 4.5 中有另一种技术,但现在找不到相关文章。
更新二:
正如我在您的代码中看到的,您正在从磁盘读取一些信息。尝试为此添加 Code Access Security 规则以查看您的代码是否 运行 受限权限,如下所示:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\example\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
有关 FileIOPermission
Class 的更多信息,请参见 MSDN。
感谢所有提出建议的人!我从来没有弄清楚到底发生了什么(如果我知道的话,我会继续 investigate/post 更新),但我最终想出了一个解决方法。
一些人建议将静态 class 的初始化内部化,但由于实际问题的性质,初始化逻辑必须外部化(我基本上是加载一个 DI/service 位置容器其成分因环境而异)。
此外,我怀疑它不会有帮助,因为我可以观察到静态构造函数被调用了两次(因此,无论有什么初始化逻辑都只会被调用两次,这并没有直接解决问题) .
不过,这个建议让我走上了正轨。
在我的例子中,我加载的 none 服务需要是有状态的,所以除了性能影响之外,初始化发生两次并不重要。
因此,我只是让静态 class 检查 MEF 容器是否已加载,如果未加载,我将读取指定 class 处理初始化的配置文件。
通过这样做,我仍然可以根据环境改变 MEF 容器的组成,目前工作得很好,即使它不是 理想 解决方案。
我想把赏金分给所有提供帮助的人,但由于这似乎不可能,我可能会奖励 OakNinja,因为他是一个英雄,能够提出尽可能多的好点子鉴于我提供的信息,这是预期的。再次感谢!