关于 c#:Access Violation Exception 在访问 Object 的字段期间

Access Violation Exception during access of field of Object

在我的 .Net Core 2.0、ASP.Net react 项目中使用 Linq 时,我遇到了一个非常奇怪的行为:

当访问在 Linq "Select" 选择器中实例化的对象的字段时,它会抛出 "Access Violation Exception"

重现步骤(希望如此):

  • 视觉工作室 2017、15.7.4
  • 创建新的 ASP.Net Core 2.0 项目
  • 选择"反应"模板
  • 改变 SampleDataController.cs 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [HttpGet("[action]")]

    public string Objects()
    {
        var rng = new Random();
        var ret = Enumerable.Range(1, 5).Select(index =>
            new TableDef("User")
                .AddField(new StringField("ID", Guid.NewGuid().ToString()))
                .AddField(new StringField("Name","User" + index.ToString()))
        );

        return"[" +
                ret.Select(x => x.ToJSONString()).Aggregate((current, next) => current +"," + next) +
           "]";
    }
  • 具有以下类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    public class TableDef
    {
        public string ID { get; private set; } = Guid.NewGuid().ToString();
        public string LockedBy { get; private set; } ="";
        public string Name { get; private set; }
        public FieldDef[] Fields { get; private set; }

        public TableDef(string name)
        {
            Name = name;
            Fields = new FieldDef[0];
        }

        public TableDef AddField(FieldDef field)
        {
            field.Parent = this;
            var flds = this.Fields;
            Array.Resize(ref flds, flds.Length + 1);
            flds[flds.Length - 1] = field;
            this.Fields = flds;
            return this;
        }

        public string ToJSONString()
        {
            return @" {""TableDef"": {""
               "
    "DefID"":""" + ID + @""",
               "
    "DefName"":""" + Name + @""",
               "
    "DefLockedBy"":""" + LockedBy + @"""}," +
                    Fields
                        .Select(x => ('"' + x.Name + @""" :""" + x.Value + '"'))
                        .Aggregate((current, next) => current +"," + next) +
               "}";
        }
    }



    public abstract class FieldDef
    {
        public string ID { get; protected set; } = Guid.NewGuid().ToString();
        public string Name { get; protected set; }
        public abstract string Value { get; set; }        
        public abstract string DefaultValue { get; set;  }
        public Boolean ReadOnly { get; protected set; } = false;
        public Boolean IsDirty { get; set; } = false;
        public TableDef Parent {
            get { return Parent; }
            set {
                this.Parent = value;
                ID = Parent.Name.Replace("","") +"_" + Name.Replace("","");
            }
        }
    }


    public class StringField : FieldDef
    {
        public override string Value {
            get { return (IsDirty) ? Value : DefaultValue; }
            set { this.Value = value; }
        }
        public override string DefaultValue { get; set; }

        public StringField(string name, string defaultValue)
        {
            Name = name;
            DefaultValue = defaultValue;
        }

        public StringField(string name, string defaultValue, Boolean readOnly)
        {
            Name = name;
            DefaultValue = defaultValue;
            ReadOnly = readOnly;
        }
    }

运行代码并单击"获取数据"链接时,应用程序完全死掉(至少在我的情况下),在 Visual Studio 中甚至没有出现错误。调试刚刚结束,给我留下以下调试输出:

1
2
3
The program '[20584] dotnet.exe: Program Trace' has exited with code 0 (0x0).
The program '[20584] dotnet.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.
The program '[20584] dotnet.exe: Managed (CoreCLR)' has exited with code -1 (0xffffffff).

当注释 public TableDef AddField(FieldDef field) 中的 field.Parent = this; 行时,代码运行顺利。可能值得注意的是,即使我在这一行设置了断点,程序也会死掉。由于这需要 2 或 3 秒,我设法从调试器的"自动"中间窗口中的字段中读取了一些变量,它们看起来非常好。一旦我尝试访问父字段,应用程序就会死掉。

我很确定这是我自己错误解释的一些继承的东西。

非常感谢任何帮助。谢谢。


好的,我发现了问题。访问冲突是由于堆栈溢出而发生的,在我看来这是违反直觉的(这就是我在这里发布它的原因)

当属性将值设置为自身时,堆栈溢出异常如何发生

由于我有 getter 和 setter 的实现,我不能再将属性用作"字段"(与仅指定 { get; set; }

时的"默认实现"相反

在实现getter和setter时需要使用单独的变量:

1
2
3
4
5
6
7
8
private TableDef _parent;
public TableDef Parent {
    get { return _parent; }
    set {
        this._parent = value;
        ID = Parent.Name.Replace("","") +"_" + Name.Replace("","");
    }
}

恕我直言,这是反直觉的,因为编译器可以"创建"这样的代码,但作为程序员你不能。


看来,您正在递归设置 Parent 属性,这将导致 2-3 秒后堆栈溢出。您可以使用私有字段来存储父对象并在属性中使用它,如下所示。

1
2
3
4
5
6
7
8
private TableDef _parent;
public TableDef Parent {
        get { return _parent; }
        set {
            this._parent = value;
            ID = this._parent.Name.Replace("","") +"_" + Name.Replace("","");
        }
    }