解析对象的最佳方法是什么?

时间:2009-07-07 19:20:16

标签: c# dependency-injection

我写了一个解析器,所以我可以拥有一个非常原始的DI框架。在框架中,我允许依赖项解析器指定在未指定或注册任何内容时要加载的默认类型。

然而,我进行默认加载的方式让我感到疑惑。我不确定我是以最好的方式做到这一点。

示例:

T LoadDefaultForType<T>()
{
    T _result = default(T);

    if (typeof(T) == typeof(ISomeThing)
    {
        result = new SomeThing();
    }
    ... more of the same
    else
    {
        throw new NotSupportException("Give me something I can work with!");
    }

    return _result;
}

更新

如果模块或程序集尚未使用具体类型配置接口,则使用此方法将获取给定接口的默认对象。

例如:

IoC.Resolve<ISomeThing>();
如果没有其他任何东西注册到ISomeThing,

将需要返回给我一个SomeThing对象。在这种情况下,LoadDefaultForType是使用默认值的最后努力(在这种情况下,无论我的域模型是什么)。

Resolve也可能对此有所了解:

T Resolve<T>()
{
    T _result = default(T);
    if (ContainedObjects.ContainsKey(typeof(T))
        _result = (T)ContainedObjects[typeof(T)];
    else
        _result = LoadDefaultForType<T>();
    return _result;
}

有什么想法?是否有更好的方法来加载默认类型,因为我正在尝试允许使用约定优于配置方法?

5 个答案:

答案 0 :(得分:2)

public T LoadDefaultForType<T>()
        where T : new()
    {
        T _result = new T();

        return _result;
    }

上面的代码会有更好的方法,但我不确定你的尝试是什么,更多的信息会帮助你更好地做任何你正在努力实现的目标。

我建议看看Unity 动态加载类型,即。依赖注入

答案 1 :(得分:2)

一些建议:

您可以创建一个可用于标记特定接口的默认实现类型的属性。当您尝试解析类型时,可以在T上搜索此属性并使用反射来动态实例化该类型。

或者,您可以使用反射来搜索可用(已加载)程序集或实现该接口的具体类型。这可能是一个缓慢且昂贵的过程,因此只有在默认情况很少的情况下才有意义。

最后,如果您对命名约定感到满意,可以搜索与接口名称相同但没有前导“I”的类。不是最好的方法,但肯定是可以在紧张的情况下工作的方法。

答案 2 :(得分:1)

如果T可以解决,那么Neil的方法是最好的(我认为它也必须在同一个程序集中?)。

在您的类中,您可以创建一个可以与System.Reflection一起使用的内部“注册表”来实例化没有巨型switch语句的项目。这样可以保留您的“约定优于配置”,同时还能让您保持干爽。

<强> 修改

结合LBushkin答案的一个方面来展示一些有效的代码。 (至少,它在我脑海中编译,并且取自我知道的一个例子......)

public T LoadDefaultForType<T>()
{
  try
  {
    string interfaceName = typeof(T).AssemblyQualifiedName;

    // Assumes that class has same name as interface, without leading I, and
    // is in ..."Classes" namespace instead of ..."Interfaces"
    string className = interfaceName.Replace("Interfaces.I", "Classes.");

    Type t = Type.GetType(className, true, true);
    System.Reflection.ConstructorInfo info = t.GetConstructor(Type.EmptyTypes);

    return (T)(info.Invoke(null));
  }
  catch
  {
    throw new NotSupportException("Give me something I can work with!");
  }
}

请注意 - 如同编写的那样 - 它不会跨程序集边界工作。它可以使用基本相同的代码完成 - 但是 - 您只需要为Type.GetType()方法提供程序集限定名称。(已修复 - 使用AssemblyQualifiedName而不是{{1}假设接口和实现类在同一个程序集中。)

答案 3 :(得分:0)

一种方法是拥有AssemblyQualifiedName对的列表,第一个包含基类型,第二个包含要实例化的子类。它可以在您的App.config或XML文件中或其他任何方便的地方。在启动期间读取此列表,并使用它来填充Dictionary以用作查找表。对于密钥,您可以使用基础的AssemblyQualifiedName,也可以使用相应的Type实例。对于该值,您可能应该考虑获取子类型的ConstructorInfo。

答案 4 :(得分:0)

加载默认类型的更好方法是提供一个将类型存储在哈希表中的add方法。这将依赖性容器与注册逻辑分离。

您可以稍后选择更改注册码以从某个文件或其他内容中读取类型。