Config dictionary for unity via XML
How can I configure a dictionary via XML with Unity container? This works:
<register type="System.Collections.Generic.Dictionary[string,int]" >
<constructor>
<param name="capacity">
<value value="10" />
</param>
</constructor>
</register>
But I need ability to add el开发者_如何学Pythonements in XML config.
Last time I tried to do that I had to use a custom converter and invent my own parser for dictionary values. I don't remember which research got me there, but here is the registration and the corresponding converter class.
<type type="IRequestPolicy" mapTo="RequestPolicyCatalog, Assembly">
<constructor>
<param name="dictionary" type="System.Collections.Generic.KeyValuePair`2[System.Int32,System.String][], mscorlib">
<array>
<value value="1, 'unauthorized'" typeConverter="Assembly.IntStringKeyValueConverter, fore.Core"/>
<value value="2, 'activation'" typeConverter="Assembly.IntStringKeyValueConverter, Quofore.Core"/>
<value value="3, 'routing'" typeConverter="Assembly.IntStringKeyValueConverter, Quofore.Core"/>
</array>
</param>
</constructor>
</type>
public class IntStringKeyValueConverter : System.ComponentModel.TypeConverter {
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
return this.ConvertFrom(context, culture, value);
}
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) {
return sourceType == typeof(string);
}
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType) {
return destinationType == typeof(KeyValuePair<int, string>);
}
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
var comma = ((string)value).IndexOf(',');
if(comma < 0)
throw new InvalidOperationException("Invalid string, must contain ',' between values");
var number = int.Parse(((string)value).Substring(0, comma));
var str = ((string)value).Substring(comma).Trim(new[] { ',', '\'', ' ' });
return new KeyValuePair<int, string>(number, str);
}
}
I believe there are several problems with the configuration you have posted:
- It appears you are trying to register an instance rather than register a type mapping. To do this you need to use the instance element rather than the register element.
The syntax you are using to specify a generic type is not correct. To specify a Dictionary<string, int> the proper syntax should be:
type="System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Int32, mscorlib]], mscorlib"
Note the `2 designates the generic type as having two type parameters.
- Specifying a value for your instance is achieved by setting the value attribute. This is a string value that must somehow be converted into a series of key value pairs for your dictionary. This will not happen by default unfortunately. You will need to write a custom converter which will accept a string and create your key/value pairs. An example of such a converter can be found here.
As a final note (and a personal preference), I'm really not a fan of using Unity for this type of object creation. I generally use a custom configuration file for any non-trivial initialization settings and use Unity strictly to register type mappings for dependency injection.
I did not try it myself, but probably you can register a bunch of instances of KeyValuePair class, and then reference them in array used as an IDictionary constructor parameter.
精彩评论