4

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 elements in XML config.

3 Answers 3

6

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);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

4

I believe there are several problems with the configuration you have posted:

  1. 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.
  2. 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.

  1. 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.

1 Comment

Unity's XML configuration supports a shorthand notation for generics. The Dictionary[string,int] syntax is valid for a Unity configuration.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.