3

我正在尝试为将注入到由我的 IoC 容器(在本例中为 Unity)创建的对象中的接口注册动态实现。

这是我正在采用的高级方法:

  1. 从 JSON 文件动态加载属性列表。我目前正在为此使用JSON.NET
  2. 将该动态对象映射到接口。我目前正在为此使用Impromptu 。
  3. 使用我的 IoC 容器为接口类型注册该动态对象

这是应该“理论上”工作的代码:

var configJson = File.ReadAllText(".\\Configuration\\DataCollector.json");
dynamic expando = JsonConvert.DeserializeObject(configJson);
var container = new UnityContainer();
var interfaceType = Type.GetType("Manufacturing.Framework.Configuration.IDataCollectorConfiguration", true);
var interfaceInstance = Impromptu.ActLike(expando, interfaceType);

container.RegisterInstance(interfaceType, "IDataCollectorConfiguration", interfaceInstance, new ContainerControlledLifetimeManager());

一切都很好,直到最后一行。Unity 不喜欢我没有给它一个实际的接口实例,只是一个鸭子类型的实例。

The type ImpromptuInterface.ActLikeCaster cannot be assigned to variables of type Manufacturing.Framework.Configuration.IDataCollectorConfiguration

我为什么要这样做?我试图通过将我的设置存储为 JSON、定义映射到该 JSON 的接口来简化我复杂的应用程序配置,然后让我的 IoC 容器自动将正确的配置注入到任何需要它的类中。

4

2 回答 2

2

如果您不需要使用接口,则可以通过使用具体类型来获得:

using System;
using Microsoft.Practices.Unity;
using Newtonsoft.Json;

namespace TestGrounds
{
    public class TestClass
    {
        #region Properties

        public int TestIntegerProperty { get; set; }

        public string TestStringProperty { get; set; }

        #endregion
    }

    internal class Program
    {
        #region Static Methods

        private static void Main(string[] args)
        {
            const string json =
                @"{ TestIntegerProperty: 1, TestStringProperty: 'Hello', AnotherTestPropertyToIgnore: 'Sup' }";

            registerDependencyFromJson<TestClass>(json);

            Console.ReadKey();
        }

        private static void registerDependencyFromJson<T>(string json) where T: class, new()
        {
            var deserializedObject = JsonConvert.DeserializeObject<T>(json);
            var type = deserializedObject.GetType();
            var container = new UnityContainer();

            container.RegisterInstance(type, type.Name, deserializedObject, new ContainerControlledLifetimeManager());
        }

        #endregion
    }
}

无论如何,这可能会更好,因为接口可能需要方法实现,任何代理都不能很好地处理(不过,我认为 Castle 有某种方法拦截器)。具体类型摆脱了那里的任何假设。唯一真正的要求是new()

更新:

这是从字符串名称创建类型的示例,并且还显示了无效类型:

using System;
using Microsoft.Practices.Unity;
using Newtonsoft.Json;

namespace TestGrounds
{
    public class TestClass
    {
        #region Properties

        public int TestIntegerProperty { get; set; }

        public string TestStringProperty { get; set; }

        #endregion
    }

    public class BadTestClass : TestClass
    {
        #region Properties

        public double TestDoubleProperty { get; set; }

        #endregion

        #region Constructors

        public BadTestClass(double testDouble)
        {
            TestDoubleProperty = testDouble;
        }

        #endregion
    }

    internal class Program
    {
        #region Static Methods

        private static void Main(string[] args)
        {
            const string json =
                @"{ TestIntegerProperty: 1, TestStringProperty: 'Hello', AnotherTestPropertyToIgnore: 'Sup' }";
            var type = Type.GetType("TestGrounds.TestClass", true);
            var badType = Type.GetType("TestGrounds.BadTestClass", true);

            registerDependencyFromJson(type, json);
            try
            {
                registerDependencyFromJson(badType, json);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }

        private static void registerDependencyFromJson(Type type, string json)
        {
            // type requires a default constructor for this to work
            var constructor = type.GetConstructor(Type.EmptyTypes);
            if(constructor == null)
            {
                throw new ArgumentException("Type must have a parameterless constructor.");
            }

            var deserializedObject = JsonConvert.DeserializeObject(json, type);
            var container = new UnityContainer();

            container.RegisterInstance(type, type.Name, deserializedObject, new ContainerControlledLifetimeManager());
        }

        #endregion
    }
}
于 2013-12-20T15:34:13.927 回答
1

ActLike用于静态类型动态对象,它至少需要对接口进行隐式强制转换。而是使用DynamicActLike,它将返回最终实例,而无需首先进行静态转换。

var interfaceInstance = Impromptu.DynamicActLike(expando, interfaceType);
于 2013-12-20T15:46:23.077 回答