Is it possible to disable run time (and compile time) checks on a class using a method call or similar? I am having trouble with my classes with invariants and using them with external libraries that construct instances dynamically. I would like to wrap those calls inside my own calls, which take a potentially partially constructed object, and returns one that is always valid.
Eg consider this code:
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace ConsoleApp
{
class Person
{
public string Name { get; set; }
public string Email { get; set; }
public string JobTitle { get; set; }
public Person(string name, string email, string title)
{
Name = name;
Email = email;
JobTitle = title;
}
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(Name != null);
Contract.Invariant(JobTitle != null);
}
}
public static class ObjectBuilder
{
// Just a sample method for building an object dynamically. In my actual code, code using
// elastic search, NEST, serializion or entity framework has similar problems.
public static T BuildFromDictionary<T>(Dictionary<string, object> dict)
{
Contract.Requires(dict != null);
T result = (T)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof (T));
foreach (var pair in dict)
{
string propName = pair.Key;
var property = typeof (T).GetProperty(propName);
property.SetValue(result, pair.Value);
}
return result;
}
}
class Program
{
public static Person CreatePerson()
{
Dictionary<string, object> personData = new Dictionary<string, object>();
personData["Name"] = "Fred";
personData["Email"] = "email@example.com";
Person person = ObjectBuilder.BuildFromDictionary<Person>(personData);
person.JobTitle = "Programmer";
return person;
}
static void Main(string[] args)
{
Person person1 = new Person("Bob", "Bob@example.com", "Hacker");
Person person = CreatePerson();
Console.WriteLine(person.Name);
}
}
}
This compiles correctly, however will throw an exception on the property.SetValue(result, pair.Value);
line. This is because it will call the Name setter, and at that stage Email
and JobTitle
are null.
What I would like to do is to disable contracts within a code section. Eg, replacing the CreatePerson
method with something like this:
public static Person CreatePerson()
{
Dictionary<string, object> personData = new Dictionary<string, object>();
personData["Name"] = "Fred";
personData["Email"] = "email@example.com";
Person person;
Contract.DisableRunTimeChecks(() =>
{
person = ObjectBuilder.BuildFromDictionary<Person>(personData);
person.JobTitle = "Programmer";
});
Contract.CheckInvariants(person);
return person;
}
Where Contract.DisableRunTimeChecks
disables run time checks for all code within that code block (and any calls made within), and Contract.CheckInvariants
runs the ContractInvariantMethod
for the given object.
Is this possible to implement somehow, or is there another solution?
One solution I have seen which I don't want to do is to introduce an _initialized
field on Person
, and making the invariant method check if that is true before doing any checks. This is because the object should always be valid except for one or two of these constructor methods.