是否误解C#类的实例隔离特性?多实例数据混乱问题求助
问题:多实例数据互相干扰,学生拿到错误的患者报告结果
我设计了一个Attainment类,用来整合各类数据、执行逻辑测试并生成输出,应用场景是学生完成患者报告后计算所得学分。原本以为类实例化后,内部所有数据与逻辑都是相互隔离的,多名学生同时完成报告、各自触发类实例化并调用学分重建方法时,不同实例的数据不会互相干扰,但实际出现了学生获取到不属于自己的患者报告结果的问题。
相关代码如下:
public class Attainment { public int StudentID { get; set; } public int PatientID { get; set; } static DataTable dtAttainmentList; static DataTable dtClassroomData; public Attainment() { dtAttainmentList = new DataTable(); dtAttainmentList.Columns.Add("boxUID", typeof(string)); dtAttainmentList.Columns.Add("type", typeof(int)); dtAttainmentList.Columns.Add("patientID", typeof(int)); } public static void Rebuild(int thisStudentID, int thisPatientID) { Attainment test = new Attainment(); test.StudentID = thisStudentID; test.PatientID = thisPatientID; test.GenerateAttainments(); } public void GenerateAttainments() { // 为简洁起见省略了其他方法,核心逻辑如下: dtClassroomData = GetClassroomData(); // 从数据库删除旧记录 // 执行新逻辑 // 向数据库插入新记录 } DataTable GetClassroomData() { // 创建新数据表 // 从数据库填充数据 // 返回数据表 } }
问题根源与解决方法
问题根源
代码里的dtAttainmentList和dtClassroomData是静态(static)成员,静态成员属于类本身,而非类的实例。所有Attainment实例都会共享这两个静态DataTable:
- 当多个学生同时触发
Rebuild时,新实例初始化会覆盖之前的dtAttainmentList - 多个实例在
GenerateAttainments中同时修改dtClassroomData,导致数据互相覆盖,最终写入数据库的是混乱的混合数据,自然出现学生拿到错误结果的情况
解决方法
把静态的dtAttainmentList和dtClassroomData改成实例成员,让每个Attainment实例拥有独立的数据表:
public class Attainment { public int StudentID { get; set; } public int PatientID { get; set; } // 去掉static修饰符,改为实例成员 DataTable dtAttainmentList; DataTable dtClassroomData; public Attainment() { dtAttainmentList = new DataTable(); dtAttainmentList.Columns.Add("boxUID", typeof(string)); dtAttainmentList.Columns.Add("type", typeof(int)); dtAttainmentList.Columns.Add("patientID", typeof(int)); } public static void Rebuild(int thisStudentID, int thisPatientID) { Attainment test = new Attainment(); test.StudentID = thisStudentID; test.PatientID = thisPatientID; test.GenerateAttainments(); } public void GenerateAttainments() { dtClassroomData = GetClassroomData(); // 从数据库删除旧记录 // 执行新逻辑 // 向数据库插入新记录 } DataTable GetClassroomData() { // 创建新数据表 // 从数据库填充数据 // 返回数据表 } }
额外注意事项:
- 如果
Rebuild在多线程环境下调用,要确保数据库操作(删旧记录、插新记录)的线程安全,比如为每个学生的操作添加事务,避免不同学生的数据库操作互相干扰 - 当前
Rebuild静态方法的逻辑没问题,每个调用都会创建独立实例,修改静态成员为实例成员后就不会有数据共享的问题了
内容的提问来源于stack exchange,提问作者andym0908
相关产品推荐
相关产品推荐

