I have the following class with a generic type parameter.
public class ContentService<T> : IContentService where T : DataString, new()
{
public ContentService(IEnvironment environment,
ILogger logger)
{
_environment = environment;
_logger = logger;
}
...
}
DataString is an abstract class and I want Structure Map to use a concrete implementation (XmlDataString) whenever my application creates an instance of ContentService. Structure Map is already injecting concrete implementations of IEnvironment and ILogger when I do this:
Version 1:
_contentService = ObjectFactory.GetInstance<ContentService<DataString>>();
... but when I step through, ContentService is created with a type parameter of DataString, not XmlDataString. I have these three entries in web.config that set default instances:
The Structure Map site has this to say about generics, but I can't seem to relate that example to my actual problem.
This approach works, but I'm losing the auto wiring of the constructor arguments and it looks quite ugly: Version 2:
Type typeOfDataString = ObjectFactory.GetInstance<DataString>().GetType();
Type genericClass = typeof(ContentService<>);
Type constructedClass = genericClass.MakeGenericType(typeOfDataString);
_contentService = (IContentService)Activator.CreateInstance(constructedClass,
ObjectFactory.GetInstance<IEnvironment>(),
ObjectFactory.GetInstance<ILogger>());
Can anyone tell me what I'm doing wrong in the first version, or how I might improve the second version?
x.For<IContentService>().Use<ContentService<XmlDataString>>();
but I haven't been able to find out how to put that in web.config (encoding the < & > doesn't work - mafue 2012-04-04 16:36
First, when you write ObjectFactory.GetInstance<ContentService<DataString>>()
, you can't get ContentService<XmlDataString>
back, because that's a different, incompatible type.
But it seems you actually want IContentService
, so write that: ObjectFactory.GetInstance<IContentService>()
. This will return the implementation of IContentService
that you registered, so you should do that: register ContentService<XmlDataString>
for IContentService
. The fact that you have XmlDataString
registered for DataString
has nothing to do with this.
If you have problems representing the generic type ContentService<XmlDataString>
in web.config, I think using the .Net representation of generic types (and not that of C#) should work. In your case, that would be something like ContentService`1[[XmlDataString]]
, probably with added namespaces and possibly assemblies too.
Just in case anyone else gets stuck on representing generic types in web.config, here's what worked for me:
<DefaultInstance
PluginType="{namespace1}.IContentService, {assembly1}"
PluggedType="{namespace2}.ContentService'1[[{namespace3}.XmlDataString, {assembly3}]], {assembly2}" />
mafue 2012-04-04 17:59
ObjectFactory.GetInstance<IContentService>()
? If that doesn't work, can't you add IContentService → ContentService