Resolving Generics via Config File

Sep 15, 2011 at 9:02 PM
Edited Sep 15, 2011 at 9:05 PM

Ok, so I'm not sure that's an accurate thread title but here goes.

I need to specify that I'd like a concrete type by providing one of it's inheritance interfaces which takes a closed type argument.  Best way to present this question is with a short example.

This is completely contrived so please look past the unnecessary complexity but it mirrors a more complex framework I'm building so here goes.

Here are my Entities:

 

 

namespace Entities
{
    public interface ITypedBirdTweeter<T> : IBirdTweeter where T : IBird, new(){}

    public interface IBirdTweeter 
    {
        string MakeAllBirdesTweet();
    }

    public abstract class BirdTweeterBase<T> : ITypedBirdTweeter<T> where T : IBird, new()
    {
        public string MakeAllBirdesTweet()
        {
            StringBuilder sb = new StringBuilder();

            foreach (T bird in GetAllBirds())
            {
                sb.Append(tweet(bird));
                sb.Append(Environment.NewLine);
            }

            return sb.ToString();
        }

        protected abstract string tweet(T birdInstance);

        private T[] GetAllBirds()
        {
            // Common code to get a bunch of T
            return new T[]{new T(), new T() };
        }
    }

    public class BigBirdTweeter : BirdTweeterBase<BigBird>
    {
        protected override string tweet(BigBird birdInstance)
        {
            //Big bird tweeter knows that big bird has a special tweet.
            return birdInstance.BigBirdsSpecialTweet;
        }
    }

    public interface IBird { }
    public class BigBird : IBird
    {
        public string BigBirdsSpecialTweet = "Big Bird Says Tweet!     ";
    }
}

So basically, I want to be able to resolve an IBirdTweeter implementation by providing an ITypedBirdTweeter<T>.  
In real life, the reason I'd like to do this is because, the type param <T> is cascading through some other code and I don't know until runtime what kind of T I'm going to be
working with.

So when my program does the following, it works :)

IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(ITypedBirdTweeter<BigBird>), typeof(BigBirdTweeter));

IBirdTweeter tweeter = container.Resolve<ITypedBirdTweeter<BigBird>>();
            Console.WriteLine(tweeter.MakeAllBirdesTweet());

The result:
Big Bird Says Tweet!     
Big Bird Says Tweet!     

But, when I try to wire this up in a config file:

 

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <containers>
      <container>
        <register
          type="Entities.ITypedBirdTweeter'1[[Entities.BigBird, Entities]], Entities"
          mapTo ="Entities.BigBirdTweeter, Entities"/>
      </container>
    </containers>
  </unity>
</configuration>

And I change the code to this:

  IUnityContainer configFileContainer=null;

  UnityConfigurationSection configSection =
                ConfigurationManager.GetSection("unity") as UnityConfigurationSection;

   try
   {
       configSection.Configure(configFileContainer);
       tweeter = configFileContainer.Resolve<ITypedBirdTweeter<BigBird>>();
       Console.WriteLine(tweeter.MakeAllBirdesTweet());
    }
    catch (Exception exc)
    {
         Console.WriteLine(exc.Message);
    }

 

I get the following exception:

System.IO.FileLoadException - "The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)"

 

Not sure what I'm doing wrong here.

Sep 20, 2011 at 3:53 AM

Hi,

It seems this is a bug with Unity as per this thread. It is already logged on the issue tracker (http://unity.codeplex.com/workitem/9784). I recommend you to upvote for it.

 

Noel Angelo Bolasoc
Avanade Software
Avanade, Inc.
Contact Us