The Equals method of the CompositionContract in the System.Composition.Runtime assembly has a bug. The Equals method will eventually internally call ConstraintEqual, which is ultimately where the bug lies.
ConstraintEqual compares two dictionaries. In most cases, there are checks for null dictionaries and null values; however, there is one uncovered case that will cause a NullReferenceException.
The following covers most scenarios:
```
if ( ( ( pair.get_Value() == null ) && ( obj2 != null ) ) || ( ( obj2 == null ) && ( pair.get_Value() != null ) ) )
{
return false;
}
```
However, if BOTH values are null, then processing continues. Eventually, you'll reach the final evaluation:
```
else if ( !pair.get_Value().Equals( obj2 ) )
{
return false;
}
```
Here lies the problem. If both of the values are null, then the Equals method is invoked on the result of KeyValuePair<,>.Value, but you'll get a NullReferenceException. The simple fix is to use the either the "==" operator or the static Object.Equals( Object, Object ) method.
This problem can arise any time you have metadata for a contract that is used multiple times and one or more of the metadata values is null.
I discovered this by expanding upon the "setting composition" example and adding a DefaultValue property to be included in the metadata. This enables composing settings, but also allows a fallback value if the setting is not present (and perhaps not required). In most scenarios, all works as expected; however, if the same setting has been resolved and is subsequently evaluated for reuse (by the lifetime context), the comparison of CompositionContract will fail due to the bug described if, and only if, the DefaultValue metadata value is null.
ConstraintEqual compares two dictionaries. In most cases, there are checks for null dictionaries and null values; however, there is one uncovered case that will cause a NullReferenceException.
The following covers most scenarios:
```
if ( ( ( pair.get_Value() == null ) && ( obj2 != null ) ) || ( ( obj2 == null ) && ( pair.get_Value() != null ) ) )
{
return false;
}
```
However, if BOTH values are null, then processing continues. Eventually, you'll reach the final evaluation:
```
else if ( !pair.get_Value().Equals( obj2 ) )
{
return false;
}
```
Here lies the problem. If both of the values are null, then the Equals method is invoked on the result of KeyValuePair<,>.Value, but you'll get a NullReferenceException. The simple fix is to use the either the "==" operator or the static Object.Equals( Object, Object ) method.
This problem can arise any time you have metadata for a contract that is used multiple times and one or more of the metadata values is null.
I discovered this by expanding upon the "setting composition" example and adding a DefaultValue property to be included in the metadata. This enables composing settings, but also allows a fallback value if the setting is not present (and perhaps not required). In most scenarios, all works as expected; however, if the same setting has been resolved and is subsequently evaluated for reuse (by the lifetime context), the comparison of CompositionContract will fail due to the bug described if, and only if, the DefaultValue metadata value is null.