Try fast search NHibernate >>>>>>>

2009/11/19

The .NET’s Attribute hole

Reading this post try to imagine how much I have worked, with my code, before create a test to test the behavior of the class Attribute.

Assertion

In .Net an Attribute is a class as any other and may have state and behavior.

True ? so and so… first of all, as class, it has some restriction as: it must inherit from System.Attribute and can’t be a generic class; second as any class it was implemented by a human with his fantasy (and this is the problem).

Perhaps, add behavior to an Attribute is not so common but, since even Microsoft is doing it, we can assume that it is a legal usage… anyway this is not the problem.

The Equal and GetHashCode issue

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
}
var attribute = new MyMarkerAttribute();
var another = new MyMarkerAttribute();
Console.WriteLine("Using == the result is: " + (attribute == another));
Console.WriteLine("Using Equals the result is:" + attribute.Equals(another));
Console.WriteLine("attribute hash:" + attribute.GetHashCode() + " another hash:" + another.GetHashCode());

This is the output:

Using == the result is: False
Using Equals the result is:True
attribute hash:10001680 another hash:10001680

Note: I haven’t implemented neither Equals nor GetHashCode. Every thing is as expected ? In a normal class this is not the expected behavior, by the way so far I can accept the situation.

Now I will change the attribute adding a integer property (about integer you know that its hash-code is its value):

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
public int Min { get; set; }
}

and now the output is:

Using == the result is: False
Using Equals the result is:True
attribute hash:0 another hash:0

What ? The HashCode now is cero ? … wait… wait… it does not end here.

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
public int Min { get; set; }
public int Max { get; set; }
}
var attribute = new MyMarkerAttribute { Min=5, Max= 456 };
var another = new MyMarkerAttribute { Min = 5, Max = 123 };

And the output is:

Using Equals the result is:False
attribute hash:5 another hash:5

As you can see the hash code is the hash of the first property (the same if it would be a field) and the most important inconsistence is that the two instance result as NOT EQUALS but they has the same HashCode.

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
private int myBergamota = 123;
public int Min { get; set; }
public int Max { get; set; }
}
var attribute = new MyMarkerAttribute {Min = 5, Max = 456};
var another = new MyMarkerAttribute { Min = 5, Max = 456 };

The output is:

Using Equals the result is:True
attribute hash:123 another hash:123

So the HashCode is the hash-code of the first property and the Equals work using the state of each property of instance of the attribute… such fantasy…

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
private int myBergamota = 123;
private int min;
public int Min
{
get { return min; }
set { min = value; }
}

public int Max { get; set; }

public void SetFieldValue()
{
myBergamota = 789;
}
}
var attribute = new MyMarkerAttribute {Min = 5, Max = 456};
var another = new MyMarkerAttribute { Min = 5, Max = 456 };

Console.WriteLine("attribute hash:" + attribute.GetHashCode() + " another hash:" + another.GetHashCode());

another.SetFieldValue();

Console.WriteLine("Using Equals the result is:" + attribute.Equals(another));
Console.WriteLine("attribute hash:" + attribute.GetHashCode() + " another hash:" + another.GetHashCode());

And the output is:

attribute hash:123 another hash:123
Using Equals the result is:False
attribute hash:123 another hash:789

What ? The hash changing at run-time ? but one of your recommendation is not that the hash-code should never change during execution ? what happen with Attribute ?

Wait a minute… who said that the hash-code change at run-time; it depend!!! depend about what… try to guess…

Now I will change only the position of the declaration of the private field:

[AttributeUsage(AttributeTargets.Property)]
public class MyMarkerAttribute: Attribute
{
private int min;
private int myBergamota = 123;
public int Min
{
get { return min; }
set { min = value; }
}

public int Max { get; set; }

public void SetFieldValue()
{
myBergamota = 789;
}
}

As you can see the only change is the position of the declaration, of the field myBergamota, from the first position to the second inside the class implementation; nothing more than the position inside the implementation!!! and now the output is:

attribute hash:5 another hash:5
Using Equals the result is:False
attribute hash:5 another hash:5

Re WHAT!???!!???! now I have the same hash-code ?!?!?!?!? only moving a declaration inside the class ?!?!?!?

Now you know that there is an ugly issue inside the .NET’s Attribute implementation and you may have a very very ugly surprise if you are writing a framework using attribute to cache metadata especially if the Attribute has behavior changing the internal state of the instance.

Resuming
The Attribute class override Equals and GetHashCode. The Equals is using the whole internal state, the GetHashCode is using only state of the first field and its value may change during execution.

The workaround
If you want a deterministic behavior the solution is simple and is the same you are applying in your classes: override Equals and GetHashCode.

If you don’t need a special behavior the implementation to use the Reference (the base of any other class) is:
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj);
}

public override int GetHashCode()
{
return RuntimeHelpers.GetHashCode(this);
}

Conclusion

I like the application of your fantasy during software development, but be moderate please.

2009/11/17

NHibernate.Validator: Tags

At the begin of NHibernate Validator we have talked about the exigency of assign a “gravity level” to each validation (for instance Error, Warning, Information). In the last year we had requests for “validation grouping” and “different validation, for the same entity, in different contexts”.

Our answer is: validation tagging

What is a tag

In NHibernate Validator a tag has de same meaning you are giving to a tag in your blog, bookmarks, feed reader, Wave and so on. This mean that each validation-constraint may have none, one or more tags.

The type of the Tag is your choice; you can use System.Type, string, enum, int or whatever you want implements IEqualityComparer and… yes!! even altogether:

public class Error { }
public class Warning { }

public enum MyEnum
{
Error,
Warining
}

public class Entity
{
[Min(Value = 20, Tags = typeof(Error))]
[Max(Tags = new[] { typeof(Error), typeof(Warning) }, Value = 100)]
public int ValueUsingTypes { get; set; }

[Min(Value = 20, Tags = "error")]
[Max(Tags = new[] { "error", "warning" }, Value = 100)]
public int ValueUsingStrings { get; set; }

[Min(Value = 20, Tags = MyEnum.Error)]
[Max(Tags = new[] { MyEnum.Error, MyEnum.Warining }, Value = 100)]
public int ValueUsingEnums { get; set; }

[Min(20)]
[Max(100)]
public int ValueWithoutTags { get; set; }
}

If you are using the XML mapping (to configure the validation), all Tags are strings but using attributes or Loquacious you can use anything you want.

Even the follow declaration is possible:

[Min(Value = 20, Tags = new object[] {typeof(Error), 1, "warning"})]

The usage on an array of object is a language limitation but, at the end, we can read it as a feature ;-) (ha a look to the end of this link).

How validate using Tags

Tags are available in any methods used, in the ValidatorEngine, to validate a property or an entity. To explain how work with Tags I prefer to show you some examples:

Example 1:
var entity = new Entity();
validatorEngine.Validate(entity);

This is the “normal” usage without tags. In this case we have four invalid values (one for each property) because without specify a tag we will use all constraints, and in this case, we are breaking all Min constraints.

Example 2:
var entity = new Entity();
validatorEngine.Validate(entity, typeof(Warning));

We have only one constraint tagged with typeof(Warning) : the property ValueUsingTypes should be less than or equal to 100. As default ValueUsingTypes=0 so, using the example2, we will have a valid entity (none invalid values).

Example 3:
var entity = new Entity {ValueUsingTypes = 101};
validatorEngine.Validate(entity, typeof (Warning));

Similar situation of the previous example but this time ValueUsingTypes is greater than 100 so we will have one invalid value.

Example 4:
var entity = new Entity();
validatorEngine.Validate(entity, typeof (Error), null);

Here I’m using two tags: typeof(Error) and the other tag is null. In this case we are selecting all constraints tagged with typeof(Error) and all constraints without tags so we will have two invalid values: ValueUsingTypes is less than 20 and ValueWithoutTags is less than 20.

In practice null is a special reserved tag used to select those constraints without a specific tag.

Example 5:
var entity = new Entity();
validatorEngine.Validate(entity, typeof(Error), MyEnum.Error, "error");

I’m using three Tags: typeof(Error), MyEnum.Error, "error". We will have three invalid values: ValueUsingTypes is less than 20 and ValueUsingStrings is less than 20 and ValueUsingEnums is less than 20.

Example 6:

To validate only those constraint without a tag the syntax is:

var entity = new Entity();
validatorEngine.Validate(entity, new object[] {null});
In this case we will have only one invalid value: ValueWithoutTags is less than 20.

Consideration

In the examples above I have used a really strange way to use Tags only to show you the freedom you having. My personal advise is to define one, two or as most three “meaning” tags. Take care with tagged and no-tagged constraints: in my opinion you should work with all tagged constraint or without tags; if you want mix tagged with no-tagged, don’t forget example-1, example-4 and example-6. If you have some constraints involving the persistence and you want run it only when all others constraints does not have invalid values, the "constraint tagging" is a good candidate to solve the issue.

The result InvalidValue with Tags

The InvalidValue class now has a new property: MatchTags. The new property will contain the intersect between the tags declared for a constraint and the tags used for a specific validation.
Example :
public static class Tags
{
public static readonly string Error = "Error";
public static readonly string Warning = "Warning";
public static readonly string Information = "Information";
}
public class Entity
{
public int ValueMinMax { get; set; }
public int ValueMin { get; set; }
}
public class EntityValidator : ValidationDef<Entity>
{
public EntityValidator()
{
Define(x => x.ValueMinMax)
.Satisfy(v => v >= 20).WithTags(Tags.Error)
.And
.Satisfy(v => v <= 100).WithTags(Tags.Error, Tags.Warning);

Define(x => x.ValueMin)
.GreaterThanOrEqualTo(20).WithTags(Tags.Warning, Tags.Information);
}
}

running a validation as

var entity = new Entity { ValueMinMax = 101 };
validatorEngine.Validate(entity, Tags.Information, Tags.Warning);

For the InvalidValue related to ValueMinMax property the MatchTags is “Warning

For the InvalidValue related to ValueMin property, the MatchTags is [“Warning”, “Information”]

2009/11/15

Refactorizing tests

I had read, in some place on the cloud, that SharpTestsEx make the test more verbose even if it is more readable.

In NHibernate.Validator (NHV) we are using #TestsEx. After implements some new features I’m improving some stuff where I’m needing a little breaking change.

This is an existing test using classic NUnit syntax:

[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
card.number = "1234567890123456";
IClassValidator classValidator = GetClassValidator(typeof(CreditCard));
InvalidValue[] invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(1, invalidValues.Length);
card.number = "541234567890125"; //right CC (luhn compliant)
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(0, invalidValues.Length);
card.ean = "9782266156066";
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(0, invalidValues.Length);
card.ean = "9782266156067";
invalidValues = classValidator.GetInvalidValues(card);
Assert.AreEqual(1, invalidValues.Length);
}

The breaking change is about the return value of GetInvalidValues : in NHV1.2.0 the method will return IEnumerable<InvalidValue>.

Refactoring step 1

Same but compileable.

[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
IClassValidator classValidator = GetClassValidator(typeof(CreditCard));

card.number = "1234567890123456";
Assert.That(classValidator.GetInvalidValues(card), Is.Not.Empty);

card.number = "541234567890125"; //right CC (luhn compliant)
Assert.That(classValidator.GetInvalidValues(card), Is.Empty);

card.ean = "9782266156066";
Assert.That(classValidator.GetInvalidValues(card), Is.Empty);

card.ean = "9782266156067";
Assert.That(classValidator.GetInvalidValues(card), Is.Not.Empty);
}
Refactoring step 2
[Test]
public void CreditCard()
{
CreditCard card = new CreditCard();
var classValidator = GetClassValidator(typeof(CreditCard));

card.number = "1234567890123456";
classValidator.GetInvalidValues(card).Should().Not.Be.Empty();

card.number = "541234567890125"; //right CC (luhn compliant)
classValidator.GetInvalidValues(card).Should().Be.Empty();

card.ean = "9782266156066"; //right EAN
classValidator.GetInvalidValues(card).Should().Be.Empty();

card.ean = "9782266156067"; //wrong EAN
classValidator.GetInvalidValues(card).Should().Not.Be.Empty();
}

Now, using SharpTestsEx, we can run the same test with xUnit, MsTests, MbUnit (if/when we will need/want change the unit test framework) and I can’t see where it is more verbose.

Refactoring step 3
[Test]
public void GivingValidState_NoInvalidValues()
{
var card = new CreditCard {Number = "541234567890125", Ean = "9782266156066"};
var classValidator = GetClassValidator(typeof(CreditCard));

classValidator.GetInvalidValues(card).Should().Be.Empty();
}

[Test]
public void GivingInvalidState_HasInvalidValues()
{
var card = new CreditCard {Number = "1234567890123456", Ean = "9782266156067"};
var classValidator = GetClassValidator(typeof(CreditCard));

classValidator.GetInvalidValues(card).Should().Have.Count.EqualTo(2);
}

Perhaps SharpTestsEx is a little bit more verbose, in some cases, but with your help we can improve it.