多个名称空间中提供相同的扩展类

时间:2014-08-01 11:39:23

标签: c# asp.net-mvc namespaces extension-methods

在MVC应用程序中,我有一个包含特定模型类的命名空间。该类实现了一个特定的接口,并且所述接口具有扩展类。

我将扩展类放在与模型类和接口相同的命名空间中,但是,除非我在视图中公开命名空间,否则扩展方法不会在视图中工作。在实际将要使用这些扩展方法的每个视图中通过using添加命名空间不是一种选择。谢天谢地I know how to globally add a namespace so it can be used inside all of views,但我有理由不将我的模型命名空间公开给他们。

考虑到这一点,我考虑将扩展方法移动到不同的命名空间,以便我可以安全地将它暴露给我的所有视图,但现在所有可以访问模型命名空间的控制器都将缺少扩展。我不想将此命名空间添加到我的所有控制器中,这次我不想让这个命名空间全局可用。如果仅将模型命名空间暴露给代码,我确实希望扩展可用。

廉价的解决方案是将相同的扩展类添加到两个名称空间(换句话说,两个具有完全相同代码的cs文件)并使用它完成,但我想尽可能使用更好的解决方案。

我想我可以继承另一个名称空间中的扩展类,但这不起作用,因为静态类不能继承任何东西。

我也尝试使用this解决方案,但它不起作用(至少对于扩展类)。我的意思是我暴露了仅包含视图扩展名的命名空间,但我在视图中的对象无法访问扩展方法。我还必须在命名空间中添加一个虚拟类(否则应用程序甚至不会注意到命名空间)。

总结一下,我有一个扩展类,我需要在两个不同的命名空间中提供。除了将所述类复制粘贴到另一个名称空间之外,还有其他方法可以实现吗?

2 个答案:

答案 0 :(得分:1)

当然,您不能在两个名称空间中使用相同的类,但是您可以使用相同的代码生成两个类。

一种方法是使用T4生成一个包含两个类的文件。 (您可能不熟悉T4。如果您使用实体框架,即使您不了解它,也可以在项目中使用它。)

将文本模板(.tt)文件添加到项目中,并使用foreach覆盖名称空间,如下所示:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>

using System;
using System.Collections.Generic;
using System.Globalization;

<#
    foreach (var @namespace in new [] { "One.Two", "First.Second" }) 
    {
#>
namespace <#= @namespace #>
{
    public static class UsefulExtensions
    {
        public static IEnumerable<String> ToTextElements(this String str)
        {
            var iter = StringInfo.GetTextElementEnumerator(str);
            while (iter.MoveNext()) 
            {
                yield return iter.GetTextElement();
            }           
        }
    }
}

<#
    }
#>

或者您可以通过将扩展名更改为.tt并将CustomTool属性设置为TextTemplatingFileGenerator并将Build Action属性设置为None来转换.cs文件。

答案 1 :(得分:1)

您可以做的一件事是在主命名空间中定义扩展方法:

namespace MyNamespace
{
    public interface ISomeInterface { }

    public static class SomeInterfaceExtensions
    {
        public static string DoSomething(this ISomeInterface someObject)
        {
            //Do something

            return "I did something";
        }
    }
}

然后在您要向视图或控制器公开的名称空间中,您可以使用只传递到主要名称的精简扩展名进行换行:

using MyNamespace;

namespace ViewAccessibleNamespace
{
    public static class SomeInterfaceExtensions
    {
        public static string DoSomethingWrapper(this ISomeInterface someObject)
        {
            return someObject.DoSomething();
        }
    }
}

using MyNamespace;

namespace ControllerAccessibleNamespace
{
    public static class SomeInterfaceExtensions
    {
        public static string DoSomethingWrapper(this ISomeInterface someObject)
        {
            return someObject.DoSomething();
        }
    }
}

这确实要求您为包装方法提供与主要方法不同的名称,但它会利用您的核心扩展代码而无需复制它。