C# 如何对命名空间进行强类型引用,而不选择其中的任意类型

C# 如何对命名空间进行强类型引用,而不选择其中的任意类型,c#,.net,dependency-injection,namespaces,C#,.net,Dependency Injection,Namespaces,我正在做一个使用依赖注入的项目。在注册一组接口和类时,我需要指出这些接口和类所在的名称空间 但我不喜欢提供字符串常量,主要是因为它会损害可重构性。我也不喜欢使用一个接口/类来获取它的名称空间。例如: typeof(FoodStore.Fruits.IApple).Namespace 因为所有这些任意类型的名称都挥之不去(为什么选择IApple而不是IOrange?)看起来很奇怪,只是为了分散代码的实际点。选择哪种类型根本没有合理的规则 我提出了以下解决方案 在我需要引用的每个命名空间中放置命名

我正在做一个使用依赖注入的项目。在注册一组接口和类时,我需要指出这些接口和类所在的名称空间

但我不喜欢提供字符串常量,主要是因为它会损害可重构性。我也不喜欢使用一个接口/类来获取它的名称空间。例如:

typeof(FoodStore.Fruits.IApple).Namespace
因为所有这些任意类型的名称都挥之不去(为什么选择
IApple
而不是
IOrange
?)看起来很奇怪,只是为了分散代码的实际点。选择哪种类型根本没有合理的规则

我提出了以下解决方案

在我需要引用的每个命名空间中放置命名空间锚类:

namespace FoodStore.Fruits
{
    /// <summary>
    ///     Serves as a type based reference to the namespace this class
    ///     is located in.
    /// </summary>
    public sealed class _NamespaceAnchor
    {
    }
}
每当我重构名称空间时,我不必担心DI注册

虽然这个解决方案满足了问题的要求,但我还是不高兴,因为现在我有了这些难看的空类。我不能让它们
内部
,因为很明显,引用跨越了程序集


我的问题是:有人知道更优雅的解决方案吗?

不,没有更好的解决方案了——就我所知,在CLR中,名称空间并不是真正的一流概念。是的,
Type
允许您向它请求一个名称空间-但是名称空间实际上是为人类而不是为虚拟机

请注意,与Java不同,在名称空间级别没有访问控制。我还没有检查,但我怀疑命名空间没有特定的元数据标记


我想不出任何名称空间在执行时会影响CLR。显然,它们会影响语言编译器——但同样,这是为了人类的利益,这样我们可以按层次结构组织类型,避免在每一步都指定层次结构。

我在这里担心的是名称空间(实际上只是类名的一部分)在应用程序中具有功能意义。如果后来的维护工程师移动了一些等级,他们可能会无意中破坏喷射系统,而没有意识到这一点。直到运行时,错误才会变得明显,并且可能需要一段时间来跟踪

在这种情况下,我更喜欢更明确的选择,比如使用属性。这里有一种可能性:

public class TestInterfaceAttribute : Attribute { }

public interface IMyInjectableService { }

[TestInterface]
public class TestService : IMyInjectableService { }

public class RealService : IMyInjectableService { }

也就是说,大多数DI框架已经有了某种形式的导出元数据(以帮助解决特定用例的正确依赖关系),或者是以一种您明确定义依赖关系解决方案的方式来构造的。

如果不是在名称空间级别,可以在程序集级别完成吗?我发现自己为每个程序集创建类似的空“标记”类的唯一目的是StructureMap引导。@David:程序集既没有名称空间,也没有默认名称空间(它是在项目级别定义的,只是Visual Studio在创建新类时使用的名称空间)@Sandor:但我认为问题的精神是一样的。现在,我的StructureMap引导程序加载了类似“y=>y.Assembly(typeof(AssemblyMarker.Assembly);”的内容,其中AssemblyMarker是该程序集中的一个空类。要注入来自不同项目的实现,引导程序需要引用每个项目。与原来的问题类似,我只是想知道是否有更好的方法来引用它。@David:是的,精神是一样的。您可以使用反射计算基本命名空间,迭代程序集中的所有类型,确定它们共同拥有的命名空间的左侧部分。不过也有一些缺陷,因为没有什么能阻止您在程序集中放置各种不一致的名称空间,所以当您遇到异常时,可能会想抛出异常。@David:我不相信C#中有任何东西会给强类型引用类型提供程序集。但我怀疑CLR中有这样一种想法,我确实意识到类型应该留在同一个名称空间中,而最终出现在另一个名称空间中的风险。但在我的例子中,非常连贯的类型以及将一个或两个名称空间移动到另一个名称空间是非常不合逻辑的。您的建议可能会避免这样的风险,但是会有意外忽略属性的风险。我非常喜欢约定而不是配置,我认为将兄弟类(在某些条件下)保持在同一名称空间中是一种明智的约定。@Sandor,如果是这样的话,我实际上喜欢您使用锚类的方法,因为这表明您的名称空间具有特殊的意义,值得考虑。如果我必须在两年后维护你的代码,看到锚类会让我在移动东西时三思而后行。锚定也将是一个方便的地方,可以附加任何元数据,这些元数据以后可能会对您的命名空间有用,无论它在您的系统中扮演什么角色(可能是用于注入的类的“类别”)。锚定上的“转到用法”也可以将您带到注入代码,特别是关于VS中的“转到使用”功能。
public class TestInterfaceAttribute : Attribute { }

public interface IMyInjectableService { }

[TestInterface]
public class TestService : IMyInjectableService { }

public class RealService : IMyInjectableService { }