在该问题中,Ahmed KRAIEM和Stephen J. Anderson都声明,如果必须始终保持与对象的状态正确性相关的检查,则应将其置于该对象内.
但是我遇到了一个实现它的问题:在将检查实现为Code Contracts的不变量之后,我不再能够使用对象初始化,AutoMapper或EntityFramework.
出现问题的原因是它们首先使用默认的空构造函数创建一个新对象,然后填充各种属性,这会触发Code Contracts的不变量,从而在运行时生成异常.
一个快速示例包含在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.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; } } } }
如果你想知道为什么有公共的Cat(int,string,bool)构造函数,如果没有使用它,就是愚弄AutoMapper.对于此示例,我需要一个构造函数来初始化整个对象,AutoMapper会识别它并自动使用它来初始化目标对象.但是,我们的数据对象没有这样的构造函数(而且,它们不能,因为它们可以具有许多属性).
唯一通过的测试是NonEmptyConstructorShouldNotThrow,其他都是(正确)失败.
出现问题的原因是它们首先使用默认的空构造函数创建一个新对象,从而在运行时生成异常.
我是否错误地使用了Code Contracts,或者在使用对象初始化,AutoMapper或EntityFramework时无法在数据对象中实现不变量?
解决方法
public Cat() { Age = 1; Name = "Cat"; }
一切都会好的.
编辑:
如Damien_The_Unbeliever的注释中所述,对象始终应处于有效状态,因此在使用默认构造函数后它可能不会处于无效状态.
因此,您必须为Age和Name设置有效值!
否则,默认构造函数完全没有任何意义,即使您计划,甚至更多甚至您承诺在以后设置属性.
唯一的另一种方法是让你的类可构建,意味着你调用一个完成初始化的方法,然后激活并使用你的合同检查方法.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。