如何更新 SaveContext 上修改和删除的实体?

2024-01-10

目标是跟踪谁更改和删除了实体。

所以我有一个实现接口的实体:

interface IAuditable {
   string ModifiedBy {get;set;}
}

class User: IAuditable {
   public int UserId {get;set;}
   public string UserName {get;set;}
   public string ModifiedBy {get;set;}
   [Timestamp]
   public byte[] RowVersion { get; set; }
}

现在实体删除操作的代码可能如下所示:

User user = context.Users.First();
user.ModifiedBy = CurrentUser.Name;
context.Users.Remove(employer);
context.SaveContext();

现实:ModifiedBy 更新将永远不会执行(当我的数据库历史触发器期望“处理”它时)。只会执行删除语句 on DB.

我想知道如果实体被修改,如何强制 EF Core“更新”已删除的实体/条目(实现特定接口)。

Note: RowVersion增加了额外的复杂性。

附: 手动进行额外的 SaveContext 调用 - 当然是一种选择,但我希望有一个通用的解决方案:许多不同的更新和删除,然后一个 SaveContext 进行所有分析。

在 SaveContext 收集之前手动更新这些属性var deletedEntries = entries.Where(e => e.State == EntityState.Deleted && isAuditable(e))它不是一个选项,因为它可能会破坏 EF Core 锁定顺序管理,从而引发死锁。

最明确的解决方案是只保留一个 SaveContext 调用,但在之前在可审计字段上注入 UPDATE 语句EF CORE call DELETE。如何实现这一目标?也许有人已经有了解决方案?

替代方案可能是“删除时不编写 DELETE 语句,而是调用可以接受可审核字段作为参数的存储过程”


我想知道如何在 EF 调用其“DELETE 语句”之前注入“UPDATE 语句”?我们有这样的API吗?

有趣的问题。在撰写本文时(EF Core 2.1.3),还没有这样的publicAPI。以下解决方案基于内部 API,幸运的是,在 EF Core 中,可以根据典型的内部 API 免责声明公开访问这些 API:

此 API 支持 Entity Framework Core 基础设施,并不适合直接在您的代码中使用。此 API 可能会在未来版本中更改或删除。

现在解决方案。负责创建修改命令的服务称为ICommandBatchPreparer https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.icommandbatchpreparer?view=efcore-2.1:

准备清单的服务修改命令批处理 https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.modificationcommandbatch?view=efcore-2.1s 表示由给定列表表示的实体更新条目 https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.iupdateentry?view=efcore-2.1s.

它包含一个名为BatchCommands https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.icommandbatchpreparer.batchcommands?view=efcore-2.1:

创建插入/更新/删除给定列表表示的实体所需的命令批处理更新条目 https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.iupdateentry?view=efcore-2.1s.

带有以下签名:

public IEnumerable<ModificationCommandBatch> BatchCommands(
    IReadOnlyList<IUpdateEntry> entries);

和默认实现CommandBatchPreparer https://github.com/aspnet/EntityFrameworkCore/blob/release/2.2/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs class.

我们将用自定义实现替换该服务,这将用“修改的”条目扩展列表,并使用基本实现来完成实际工作。由于批处理基本上是按依赖关系排序的修改命令列表,然后by type with Delete之前Update,我们将首先对更新命令使用单独的批次,然后连接其余的命令。

生成的修改命令基于IUpdateEntry https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.update.iupdateentry?view=efcore-2.1:

传递给数据库提供程序以将对实体所做的更改保存到数据库的信息。

幸运的是,它是一个接口,因此我们将为附加的“修改”条目及其相应的删除条目提供我们自己的实现(稍后会详细介绍)。

首先,我们将创建一个基本实现,它只是将调用委托给底层对象,从而允许我们稍后仅重写对于我们想要实现的目标至关重要的方法:

class DelegatingEntry : IUpdateEntry
{
    public DelegatingEntry(IUpdateEntry source) { Source = source; }
    public IUpdateEntry Source { get; }
    public virtual IEntityType EntityType => Source.EntityType;
    public virtual EntityState EntityState => Source.EntityState;
    public virtual IUpdateEntry SharedIdentityEntry => Source.SharedIdentityEntry;
    public virtual object GetCurrentValue(IPropertyBase propertyBase) => Source.GetCurrentValue(propertyBase);
    public virtual TProperty GetCurrentValue<TProperty>(IPropertyBase propertyBase) => Source.GetCurrentValue<TProperty>(propertyBase);
    public virtual object GetOriginalValue(IPropertyBase propertyBase) => Source.GetOriginalValue(propertyBase);
    public virtual TProperty GetOriginalValue<TProperty>(IProperty property) => Source.GetOriginalValue<TProperty>(property);
    public virtual bool HasTemporaryValue(IProperty property) => Source.HasTemporaryValue(property);
    public virtual bool IsModified(IProperty property) => Source.IsModified(property);
    public virtual bool IsStoreGenerated(IProperty property) => Source.IsStoreGenerated(property);
    public virtual void SetCurrentValue(IPropertyBase propertyBase, object value) => Source.SetCurrentValue(propertyBase, value);
    public virtual EntityEntry ToEntityEntry() => Source.ToEntityEntry();
}

现在第一个自定义条目:

class AuditUpdateEntry : DelegatingEntry
{
    public AuditUpdateEntry(IUpdateEntry source) : base(source) { }
    public override EntityState EntityState => EntityState.Modified;
    public override bool IsModified(IProperty property)
    {
        if (property.Name == nameof(IAuditable.ModifiedBy)) return true;
        return false;
    }
    public override bool IsStoreGenerated(IProperty property)
        => property.ValueGenerated.ForUpdate()
            && (property.AfterSaveBehavior == PropertySaveBehavior.Ignore
                || !IsModified(property));
}

首先我们“修改”源状态Deleted to Modified。然后我们修改IsModified返回的方法false for Deleted要返回的条目true用于可审核属性,从而强制将它们包含在更新命令中。最后我们修改IsStoreGenerated方法也返回false for Deleted条目返回相应的结果Modified条目(EF 核心代码 https://github.com/aspnet/EntityFrameworkCore/blob/release/2.2/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs#L1146)。这是让 EF Core 正确处理更新时数据库生成的值所必需的,例如RowVersion。执行命令后,EF Core会调用SetCurrentValue与从数据库返回的值。正常情况下不会发生这种情况Deleted条目和正常Modified条目传播到它们的实体。

这导致我们需要第二个自定义条目,它将包装原始条目,并且也将用作AuditUpdateEntry,因此将收到SetCurrentValue从中。它将在内部存储接收到的值,从而保持原始实体状态不变,并将它们视为“当前”和“原始”。这一点很重要,因为删除命令将在更新后执行,并且如果RowVersion不返回新值作为“原始”,生成的删除命令将失败。

这是实现:

class AuditDeleteEntry : DelegatingEntry
{
    public AuditDeleteEntry(IUpdateEntry source) : base(source) { }
    Dictionary<IPropertyBase, object> updatedValues;
    public override object GetCurrentValue(IPropertyBase propertyBase)
    {
        if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
            return value;
        return base.GetCurrentValue(propertyBase);
    }
    public override object GetOriginalValue(IPropertyBase propertyBase)
    {
        if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
            return value;
        return base.GetOriginalValue(propertyBase);
    }
    public override void SetCurrentValue(IPropertyBase propertyBase, object value)
    {
        if (updatedValues == null) updatedValues = new Dictionary<IPropertyBase, object>();
        updatedValues[propertyBase] = value;
    }
}

有了这两个自定义条目,我们就可以实现自定义命令批处理生成器了:

class AuditableCommandBatchPreparer : CommandBatchPreparer
{
    public AuditableCommandBatchPreparer(CommandBatchPreparerDependencies dependencies) : base(dependencies) { }

    public override IEnumerable<ModificationCommandBatch> BatchCommands(IReadOnlyList<IUpdateEntry> entries)
    {
        List<IUpdateEntry> auditEntries = null;
        List<AuditUpdateEntry> auditUpdateEntries = null;
        for (int i = 0; i < entries.Count; i++)
        {
            var entry = entries[i];
            if (entry.EntityState == EntityState.Deleted && typeof(IAuditable).IsAssignableFrom(entry.EntityType.ClrType))
            {
                if (auditEntries == null)
                {
                    auditEntries = entries.Take(i).ToList();
                    auditUpdateEntries = new List<AuditUpdateEntry>();
                }
                var deleteEntry = new AuditDeleteEntry(entry);
                var updateEntry = new AuditUpdateEntry(deleteEntry);
                auditEntries.Add(deleteEntry);
                auditUpdateEntries.Add(updateEntry);
            }
            else
            {
                auditEntries?.Add(entry);
            }
        }
        return auditEntries != null ?
            base.BatchCommands(auditUpdateEntries).Concat(base.BatchCommands(auditEntries)) :
            base.BatchCommands(entries);
    }
}

我们快完成了。添加一个帮助方法来注册我们的服务:

public static class AuditableExtensions
{
    public static DbContextOptionsBuilder AddAudit(this DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.ReplaceService<ICommandBatchPreparer, AuditableCommandBatchPreparer>();
        return optionsBuilder;
    }
}

并从你那里调用它DbContext派生类OnConfiguring覆盖:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    // ...
    optionsBuilder.AddAudit();
}

你就完成了。

所有这些都是为了手动填充单个可审核字段以了解想法。它可以扩展更多可审计字段,注册自定义可审计字段提供程序服务并自动填充插入/更新/删除操作等的值。


P.S.完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Update;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Auditable.Internal; 

namespace Auditable
{
    public interface IAuditable
    {
        string ModifiedBy { get; set; }
    }

    public static class AuditableExtensions
    {
        public static DbContextOptionsBuilder AddAudit(this DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.ReplaceService<ICommandBatchPreparer, AuditableCommandBatchPreparer>();
            return optionsBuilder;
        }
    }
}

namespace Auditable.Internal
{
    class AuditableCommandBatchPreparer : CommandBatchPreparer
    {
        public AuditableCommandBatchPreparer(CommandBatchPreparerDependencies dependencies) : base(dependencies) { }

        public override IEnumerable<ModificationCommandBatch> BatchCommands(IReadOnlyList<IUpdateEntry> entries)
        {
            List<IUpdateEntry> auditEntries = null;
            List<AuditUpdateEntry> auditUpdateEntries = null;
            for (int i = 0; i < entries.Count; i++)
            {
                var entry = entries[i];
                if (entry.EntityState == EntityState.Deleted && typeof(IAuditable).IsAssignableFrom(entry.EntityType.ClrType))
                {
                    if (auditEntries == null)
                    {
                        auditEntries = entries.Take(i).ToList();
                        auditUpdateEntries = new List<AuditUpdateEntry>();
                    }
                    var deleteEntry = new AuditDeleteEntry(entry);
                    var updateEntry = new AuditUpdateEntry(deleteEntry);
                    auditEntries.Add(deleteEntry);
                    auditUpdateEntries.Add(updateEntry);
                }
                else
                {
                    auditEntries?.Add(entry);
                }
            }
            return auditEntries != null ?
                base.BatchCommands(auditUpdateEntries).Concat(base.BatchCommands(auditEntries)) :
                base.BatchCommands(entries);
        }
    }

    class AuditUpdateEntry : DelegatingEntry
    {
        public AuditUpdateEntry(IUpdateEntry source) : base(source) { }
        public override EntityState EntityState => EntityState.Modified;
        public override bool IsModified(IProperty property)
        {
            if (property.Name == nameof(IAuditable.ModifiedBy)) return true;
            return false;
        }
        public override bool IsStoreGenerated(IProperty property)
            => property.ValueGenerated.ForUpdate()
                && (property.AfterSaveBehavior == PropertySaveBehavior.Ignore
                    || !IsModified(property));
    }

    class AuditDeleteEntry : DelegatingEntry
    {
        public AuditDeleteEntry(IUpdateEntry source) : base(source) { }
        Dictionary<IPropertyBase, object> updatedValues;
        public override object GetCurrentValue(IPropertyBase propertyBase)
        {
            if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
                return value;
            return base.GetCurrentValue(propertyBase);
        }
        public override object GetOriginalValue(IPropertyBase propertyBase)
        {
            if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
                return value;
            return base.GetOriginalValue(propertyBase);
        }
        public override void SetCurrentValue(IPropertyBase propertyBase, object value)
        {
            if (updatedValues == null) updatedValues = new Dictionary<IPropertyBase, object>();
            updatedValues[propertyBase] = value;
        }
    }

    class DelegatingEntry : IUpdateEntry
    {
        public DelegatingEntry(IUpdateEntry source) { Source = source; }
        public IUpdateEntry Source { get; }
        public virtual IEntityType EntityType => Source.EntityType;
        public virtual EntityState EntityState => Source.EntityState;
        public virtual IUpdateEntry SharedIdentityEntry => Source.SharedIdentityEntry;
        public virtual object GetCurrentValue(IPropertyBase propertyBase) => Source.GetCurrentValue(propertyBase);
        public virtual TProperty GetCurrentValue<TProperty>(IPropertyBase propertyBase) => Source.GetCurrentValue<TProperty>(propertyBase);
        public virtual object GetOriginalValue(IPropertyBase propertyBase) => Source.GetOriginalValue(propertyBase);
        public virtual TProperty GetOriginalValue<TProperty>(IProperty property) => Source.GetOriginalValue<TProperty>(property);
        public virtual bool HasTemporaryValue(IProperty property) => Source.HasTemporaryValue(property);
        public virtual bool IsModified(IProperty property) => Source.IsModified(property);
        public virtual bool IsStoreGenerated(IProperty property) => Source.IsStoreGenerated(property);
        public virtual void SetCurrentValue(IPropertyBase propertyBase, object value) => Source.SetCurrentValue(propertyBase, value);
        public virtual EntityEntry ToEntityEntry() => Source.ToEntityEntry();
    }
}

Update:EF Core 5 更新的完整代码(未经测试):

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Update;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Auditable.Internal;

namespace Auditable
{
    public interface IAuditable
    {
        string ModifiedBy { get; set; }
    }

    public static class AuditableExtensions
    {
        public static DbContextOptionsBuilder AddAudit(this DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.ReplaceService<ICommandBatchPreparer, AuditableCommandBatchPreparer>();
            return optionsBuilder;
        }
    }
}

namespace Auditable.Internal
{
    class AuditableCommandBatchPreparer : CommandBatchPreparer
    {
        public AuditableCommandBatchPreparer(CommandBatchPreparerDependencies dependencies) : base(dependencies) { }

        public override IEnumerable<ModificationCommandBatch> BatchCommands(IList<IUpdateEntry> entries, IUpdateAdapter updateAdapter)
        {
            List<IUpdateEntry> auditEntries = null;
            List<IUpdateEntry> auditUpdateEntries = null;
            for (int i = 0; i < entries.Count; i++)
            {
                var entry = entries[i];
                if (entry.EntityState == EntityState.Deleted && typeof(IAuditable).IsAssignableFrom(entry.EntityType.ClrType))
                {
                    if (auditEntries == null)
                    {
                        auditEntries = entries.Take(i).ToList();
                        auditUpdateEntries = new List<IUpdateEntry>();
                    }
                    var deleteEntry = new AuditDeleteEntry(entry);
                    var updateEntry = new AuditUpdateEntry(deleteEntry);
                    auditEntries.Add(deleteEntry);
                    auditUpdateEntries.Add(updateEntry);
                }
                else
                {
                    auditEntries?.Add(entry);
                }
            }
            return auditEntries != null ?
                base.BatchCommands(auditUpdateEntries, updateAdapter).Concat(base.BatchCommands(auditEntries, updateAdapter)) :
                base.BatchCommands(entries, updateAdapter);
        }
    }

    class AuditUpdateEntry : DelegatingEntry
    {
        public AuditUpdateEntry(IUpdateEntry source) : base(source) { }
        public override EntityState EntityState => EntityState.Modified;
        public override bool IsModified(IProperty property)
        {
            if (property.Name == nameof(IAuditable.ModifiedBy)) return true;
            return false;
        }
        public override bool IsStoreGenerated(IProperty property)
            => property.ValueGenerated.ForUpdate()
                && (property.GetAfterSaveBehavior() == PropertySaveBehavior.Ignore
                    || !IsModified(property));
    }

    class AuditDeleteEntry : DelegatingEntry
    {
        public AuditDeleteEntry(IUpdateEntry source) : base(source) { }
        Dictionary<IPropertyBase, object> updatedValues;
        public override object GetCurrentValue(IPropertyBase propertyBase)
        {
            if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
                return value;
            return base.GetCurrentValue(propertyBase);
        }
        public override object GetOriginalValue(IPropertyBase propertyBase)
        {
            if (updatedValues != null && updatedValues.TryGetValue(propertyBase, out var value))
                return value;
            return base.GetOriginalValue(propertyBase);
        }
        public override void SetStoreGeneratedValue(IProperty property, object value)
        {
            if (updatedValues == null) updatedValues = new Dictionary<IPropertyBase, object>();
            updatedValues[property] = value;
        }
    }

    class DelegatingEntry : IUpdateEntry
    {
        public DelegatingEntry(IUpdateEntry source) { Source = source; }
        public IUpdateEntry Source { get; }
        public virtual IEntityType EntityType => Source.EntityType;
        public virtual EntityState EntityState { get => Source.EntityState; set => Source.EntityState = value; }
        public virtual IUpdateEntry SharedIdentityEntry => Source.SharedIdentityEntry;
        public virtual object GetCurrentValue(IPropertyBase propertyBase) => Source.GetCurrentValue(propertyBase);
        public virtual TProperty GetCurrentValue<TProperty>(IPropertyBase propertyBase) => Source.GetCurrentValue<TProperty>(propertyBase);
        public virtual object GetOriginalValue(IPropertyBase propertyBase) => Source.GetOriginalValue(propertyBase);
        public virtual TProperty GetOriginalValue<TProperty>(IProperty property) => Source.GetOriginalValue<TProperty>(property);
        public virtual object GetPreStoreGeneratedCurrentValue(IPropertyBase propertyBase) => Source.GetPreStoreGeneratedCurrentValue(propertyBase);
        public virtual object GetRelationshipSnapshotValue(IPropertyBase propertyBase) => Source.GetRelationshipSnapshotValue(propertyBase);
        public virtual bool HasTemporaryValue(IProperty property) => Source.HasTemporaryValue(property);
        public virtual bool IsConceptualNull(IProperty property) => Source.IsConceptualNull(property);
        public virtual bool IsModified(IProperty property) => Source.IsModified(property);
        public virtual bool IsStoreGenerated(IProperty property) => Source.IsStoreGenerated(property);
        public virtual void SetOriginalValue(IProperty property, object value) => Source.SetOriginalValue(property, value);
        public virtual void SetPropertyModified(IProperty property) => Source.SetPropertyModified(property);
        public virtual void SetStoreGeneratedValue(IProperty property, object value) => Source.SetStoreGeneratedValue(property, value);
        public virtual EntityEntry ToEntityEntry() => Source.ToEntityEntry();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何更新 SaveContext 上修改和删除的实体? 的相关文章

  • Windows 8中有没有特殊的API来挂载ISO文件?

    您可能知道 Windows 资源管理器允许将 ISO 文件装载到虚拟驱动器 有没有任何API可以用来做到这一点 本机函数调用AttachVirtualDisk https msdn microsoft com en us library w
  • C# 中两种不同类型的列表

    我目前在为客户提供购物车时遇到问题 他希望能够在 CartItems 之间添加文本 所以我想知道是否有某种方法仍然只有一个列表 我的解决方案是有两个列表 其中一个是 IList 类型 在计算购物车的重量和总体价格时会迭代 而另一个 ILis
  • C# 锁(mylocker) 不起作用

    我有很多 Web 服务调用 异步 在回调中 我会将结果绘制到 Excel 中 我想同步绘图方法 所以我使用以下内容 但是 从我在 Visual Studio 中追踪到 每次 lock locker 都会成功 并且有许多线程运行clearco
  • C 语言中的套接字如何工作?

    我对 C 中的套接字编程有点困惑 You create a socket bind it to an interface and an IP address and get it to listen I found a couple of
  • 纹理映射 C++ OpenGL

    我已经阅读了相关内容 包括 Nehe 和此处的解决方案 但我找不到具体的答案 我正在尝试加载一张名为stars jpg 的照片 我想通过使用 uv 坐标映射它来使其成为场景的背景 方法是 glBegin GL QUADS glTexCoor
  • 使用 C# 和反射打印完整的对象图

    我有一个复杂的对象 class A int Field1 int field2 property ClassB ClassB property classC classC etc etc 我想使用反射打印完整的对象图 有什么好的代码吗 一种
  • 在 PHP 扩展中,推荐从 std::string 返回值的方法

    我们有一个简单的 PHP 函数 其目的是调用 C 自由函数std string callLibrary std string 并返回其std string返回值 目前看起来是这样的 PHP FUNCTION call library cha
  • Apple IOS 上的 C# 应用程序 [已关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有基于 C Net 的应用程序 有什么方法可以在 Apple IOS 上运行这些应用程序吗 我没有资
  • 获取进程的所有 DLL

    我想获取为给定进程加载的所有 dll 的列表 我目前正在使用 NET框架4 0 我知道有一个bug https connect microsoft com VisualStudio feedback details 546430 syste
  • 如何使用 Linq to Sql 修剪值?

    在数据库中 我有一个名为 联系人 的表 名字和其他此类字符串字段设计为使用 Char 数据类型 不是我的数据库设计 我的对象 Contact 映射到属性中的字符串类型 如果我想做一个简单的测试 通过 id 检索 Contact 对象 我会这
  • C++中的虚方法表存放在哪里?

    我想知道类对象 不是实例 而是类 如何存储在内存中 class A public int a virtual void f virtual A class B public A public int b void f final overr
  • vs2010 c++ 通过debug查看指针内容

    我正在使用 Vs2010 c 处理 2D 数组 我从一维指针开始 并使用操作 如下 class CMatrix void clear public int nRows int nCols short MyMat CMatrix CMatri
  • 在 Ubuntu 16.04 上编译 PCL 1.7,CMake 生成的 Makefile 中出现错误

    我正在尝试让 PCL 1 7 点云库 而不是其他 pcl 在 Ubuntu 16 04 上运行 我最终希望用于 C 的东西 但现在我只是想让这些例子工作 我使用的是 Ubuntu GNU 5 3 1 附带的默认编译器和 Cmake 版本 3
  • 初始化二维数组时出现分段错误

    我已经检查过我的代码是否正确地划分了内存空间 但是一旦我尝试将 2D 数组初始化为某些值 然后对这些值求和 我就会在 2x2 数组上收到分段错误 我想最终将我的代码扩展到更大的数组 但我什至无法让它在这里工作 我知道有很多关于 malloc
  • AllowUserToAddRows 不适用于 DataGridView 上的 List<> 数据源

    我有一个DataGridView与DataSource set to List
  • 使用客户端 hello 消息进行 TLS 协议检测

    我需要检测网络流量中的 https 数据包 到目前为止 我将所有 443 标记为 https 但我不想再在这种情况下使用端口信息 检查客户端问候消息是否足够 Check 22 and version info 0300 0301 or 03
  • XSD、泛型和 C# 类的困境

    我有以下简单的 XSD 文件
  • 比较 C# 中的对象属性[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案或互动
  • Eclipse CDT C/C++:包含另一个项目的头文件

    我在 Eclipse CDT 中有两个 C 项目main and shared In shared我有一个名为calc h 我想在中使用这个标头main 所以我做了以下事情 added include calc h到相关文件main In
  • 如何将 IDispatch* 放入托管代码中

    我一直在考虑尝试使用 C 编写一个实现 OPOS 服务对象的 COM 对象 我已经使用自动化和 MFC 在 C 中完成了它 这并不太困难 所以我坚持尝试将其转换为一种方法 我将排除界面中的其他方法 因为它们很简单 或者我希望如此 id 6

随机推荐