在多个线程中实例化非静态 class 时出现对象引用错误
Object reference error while instantiating non static class in multiple threads
我正在使用 C# 和 NUnit 框架在单独的线程中同时执行多个测试。我想记录某些动作之间的时间,并为此创建了一个 ActionTimeHelper class。
下面是 class 的代码以及使用 class 中的方法的上下文
当我 运行 两个并行测试调用 Login 方法时,只有一个测试完成,另一个抛出错误
(Message: System.NullReferenceException : Object reference not set to an instance of an object.
) at actionList.Add(new ActionTimeInfo()
我已经将 actionList 设置为 ThreadStatic,这样每个 运行 在自己线程上的测试都有自己的副本,所以我无法弄清楚为什么会出现错误。
注意:如果我 运行 一次测试一个,一切正常
有人可以指导我吗?感谢您的帮助。
已阅读一些文章Referencing a non static member with an instantiated object, Referencing an instantiated object in a static class (c#)但无法解决我的具体问题
public static class ActionTimeHelper
{
private static readonly string _actionTimeLogFileName = "ActionTimeLog_" + string.Format("{0:yyyy_MM_dd_hhmmss}", DateTime.Now);
[ThreadStatic] private static FileStream _fileStream = null;
[ThreadStatic] private static StreamWriter _actionStreamWriter = null;
[ThreadStatic] private static JsonWriter _jsonWriter = null;
[ThreadStatic] private static List<ActionTimeInfo> actionList = new List<ActionTimeInfo>();
public static void CreateActionTimeLogFile(string logPath, string testName)
{
string dir = logPath + testName + @"\";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
_fileStream = File.Open(dir + _actionTimeLogFileName + ".json", FileMode.CreateNew);
_actionStreamWriter = new StreamWriter(_fileStream);
_jsonWriter = new JsonTextWriter(_actionStreamWriter);
_jsonWriter.Formatting = Formatting.Indented;
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(_jsonWriter, actionList);
_fileStream.Flush();
_actionStreamWriter.Flush();
_jsonWriter.Flush();
}
public static void StartActionTime(string actionName)
{
actionList.Add(new ActionTimeInfo()
{
TestName = TestContext.CurrentContext.Test.Name,
ActionName = actionName,
StartTime = DateTime.Now
});
}
public static void EndActionTime(string actionName)
{
ActionTimeInfo endAction = actionList.Find(actionInfo => actionInfo.ActionName.Equals(actionName));
endAction.EndTime = DateTime.Now;
endAction.ExecutionTime = endAction.EndTime.Subtract(endAction.StartTime);
}
}
public class ActionTimeInfo
{
public string TestName { get; set; }
public string ActionName { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan ExecutionTime { get; set; }
}
public void Login(string username, string password)
{
ActionTimeHelper.StartActionTime("Navigating to URL");
ActionTimeHelper.EndActionTime("Navigating to URL");
ActionTimeHelper.StartActionTime("Login Action");
ActionTimeHelper.EndActionTime("Login Action");
Thread.Sleep(30000);
}
[TearDown]
public void TestTearDown()
{
ActionTimeHelper.CreateActionTimeLogFile(LogPath, TestContext.CurrentContext.Test.Name);
}
实际结果:空引用错误
预期结果:无空引用错误
“不要为标有ThreadStaticAttribute的字段指定初始值,因为这样的初始化只会在class构造函数执行时发生一次,因此只会影响一个线程。如果不指定初始值,则可以依赖字段被初始化为其默认值(如果它是值类型)或初始化为 null(如果它是引用类型)。“
来自
https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.8
我正在使用 C# 和 NUnit 框架在单独的线程中同时执行多个测试。我想记录某些动作之间的时间,并为此创建了一个 ActionTimeHelper class。
下面是 class 的代码以及使用 class 中的方法的上下文
当我 运行 两个并行测试调用 Login 方法时,只有一个测试完成,另一个抛出错误
(Message: System.NullReferenceException : Object reference not set to an instance of an object.
) at actionList.Add(new ActionTimeInfo()
我已经将 actionList 设置为 ThreadStatic,这样每个 运行 在自己线程上的测试都有自己的副本,所以我无法弄清楚为什么会出现错误。
注意:如果我 运行 一次测试一个,一切正常
有人可以指导我吗?感谢您的帮助。
已阅读一些文章Referencing a non static member with an instantiated object, Referencing an instantiated object in a static class (c#)但无法解决我的具体问题
public static class ActionTimeHelper
{
private static readonly string _actionTimeLogFileName = "ActionTimeLog_" + string.Format("{0:yyyy_MM_dd_hhmmss}", DateTime.Now);
[ThreadStatic] private static FileStream _fileStream = null;
[ThreadStatic] private static StreamWriter _actionStreamWriter = null;
[ThreadStatic] private static JsonWriter _jsonWriter = null;
[ThreadStatic] private static List<ActionTimeInfo> actionList = new List<ActionTimeInfo>();
public static void CreateActionTimeLogFile(string logPath, string testName)
{
string dir = logPath + testName + @"\";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
_fileStream = File.Open(dir + _actionTimeLogFileName + ".json", FileMode.CreateNew);
_actionStreamWriter = new StreamWriter(_fileStream);
_jsonWriter = new JsonTextWriter(_actionStreamWriter);
_jsonWriter.Formatting = Formatting.Indented;
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(_jsonWriter, actionList);
_fileStream.Flush();
_actionStreamWriter.Flush();
_jsonWriter.Flush();
}
public static void StartActionTime(string actionName)
{
actionList.Add(new ActionTimeInfo()
{
TestName = TestContext.CurrentContext.Test.Name,
ActionName = actionName,
StartTime = DateTime.Now
});
}
public static void EndActionTime(string actionName)
{
ActionTimeInfo endAction = actionList.Find(actionInfo => actionInfo.ActionName.Equals(actionName));
endAction.EndTime = DateTime.Now;
endAction.ExecutionTime = endAction.EndTime.Subtract(endAction.StartTime);
}
}
public class ActionTimeInfo
{
public string TestName { get; set; }
public string ActionName { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan ExecutionTime { get; set; }
}
public void Login(string username, string password)
{
ActionTimeHelper.StartActionTime("Navigating to URL");
ActionTimeHelper.EndActionTime("Navigating to URL");
ActionTimeHelper.StartActionTime("Login Action");
ActionTimeHelper.EndActionTime("Login Action");
Thread.Sleep(30000);
}
[TearDown]
public void TestTearDown()
{
ActionTimeHelper.CreateActionTimeLogFile(LogPath, TestContext.CurrentContext.Test.Name);
}
实际结果:空引用错误 预期结果:无空引用错误
“不要为标有ThreadStaticAttribute的字段指定初始值,因为这样的初始化只会在class构造函数执行时发生一次,因此只会影响一个线程。如果不指定初始值,则可以依赖字段被初始化为其默认值(如果它是值类型)或初始化为 null(如果它是引用类型)。“
来自
https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.8