gpt4 book ai didi

c# - 是否可以在数据对象中使用代码契约的不变量?

转载 作者:行者123 更新时间:2023-11-30 12:46:29 24 4
gpt4 key购买 nike

这个问题直接源于Validating parameters properties with Code Contracts .

在那个问题中Ahmed KRAIEMStephen J. Anderson声明与对象的状态正确性有关的检查如果必须始终保持,则应放在该对象内。

但是我在实现它时遇到了一个问题:在将检查实现为代码契约的不变量之后,我无法再使用对象初始化、AutoMapper 或 EntityFramework。

问题的出现是因为它们首先使用默认的空构造函数创建一个新对象,然后填充各种属性,这会触发代码契约的不变量在运行时生成异常。

包含在 Visual Studio 单元测试中的快速示例(您需要通过 NuGet 添加 AutoMapper 才能使其工作):

namespace Playground.Sandbox
{
using System.Diagnostics.Contracts;

using AutoMapper;

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class ContractTest
{
private const int CatAge = 5;
private const string CatName = "Tama";
private const int DogAge = 10;
private const string DogName = "Poochi";

static ContractTest()
{
Mapper.CreateMap<Dog, Cat>();
}

[TestMethod]
public void EmptyConstructorShouldThrow()
{
var cat = new Cat();

Assert.AreEqual(default(int), cat.Age);
Assert.AreEqual(default(string), cat.Name);
}

[TestMethod]
public void NonEmptyConstructorShouldNotThrow()
{
var cat = new Cat(CatAge, CatName, true);

Assert.AreEqual(CatAge, cat.Age);
Assert.AreEqual(CatName, cat.Name);
}

[TestMethod]
public void ObjectInitializerShouldThrow()
{
var cat = new Cat { Age = CatAge, Name = CatName };

Assert.AreEqual(CatAge, cat.Age);
Assert.AreEqual(CatName, cat.Name);
}

[TestMethod]
public void AutoMapperConversionShouldThrow()
{
var dog = new Dog { Age = DogAge, Name = DogName };
var cat = Mapper.Map<Dog, Cat>(dog);

Assert.AreEqual(DogAge, cat.Age);
Assert.AreEqual(DogName, cat.Name);
}

private class Cat
{
public Cat()
{
}

public Cat(int age, string name, bool doesMeow)
{
this.Age = age;
this.Name = name;
}

public int Age { get; set; }

public string Name { get; set; }

[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(this.Age > 0);
Contract.Invariant(!string.IsNullOrWhiteSpace(this.Name));
}
}

private class Dog
{
public int Age { get; set; }

public string Name { get; set; }
}
}
}

如果您想知道为什么没有使用 public Cat(int, string, bool) 构造函数,那是为了愚弄 AutoMapper。对于这个例子,我需要一个构造函数来初始化整个对象,AutoMapper 识别它并自动使用它来初始化目标对象。然而,我们的数据对象没有这样的构造函数(而且,它们不能,因为它们可以有几十个属性)。

唯一通过的测试是 NonEmptyConstructorShouldNotThrow,其他的都(正确地)失败了。

问题的出现是因为它们首先使用默认的空构造函数创建一个新对象,然后填充各种属性,这会触发代码契约的不变量在运行时生成异常。

在使用对象初始化、AutoMapper 或 EntityFramework 时,我是否错误地使用了代码契约,或者没有办法在数据对象中实现不变量?

最佳答案

Cat 的默认构造函数中设置有效值,如下所示:

public Cat()
{
Age = 1;
Name = "Cat";
}

一切都会好起来的。

编辑:正如 Damien_The_Unbeliever 的评论所述,对象始终 应该处于有效状态,因此在使用默认构造函数后它可能不会处于无效状态。

因此,您必须AgeName 设置有效值!

否则,默认构造函数根本没有意义,即使您计划这样做,甚至您 promise 在之后的某个时候设置您的属性。

唯一的另一种方法是让你的类成为可构建,这意味着你调用一个完成初始化并激活的方法,然后使用你的契约(Contract)检查方法.

关于c# - 是否可以在数据对象中使用代码契约的不变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20002388/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com