简体   繁体   English

在多个名称空间中可用的相同扩展类

[英]Same extension class available in multiple namespaces

In an MVC application I have a namespace that contains specific model class. 在MVC应用程序中,我有一个包含特定模型类的名称空间。 This class implements a specific interface and said interface has an extension class. 此类实现特定的接口,并且所述接口具有扩展类。

I put the extension class inside the same namespace as the model class and interface, however, the extension methods won't work in views unless I expose the namespace inside the views. 我将扩展类放在与模型类和接口相同的名称空间中,但是,除非将名称空间公开在视图中,否则扩展方法在视图中将不起作用。 Adding the namespace through using in each and every view that is actually going to use those extension methods is not an option. 通过在实际上将要使用这些扩展方法的每个视图中using添加名称空间不是一种选择。 Thankfully I know how to globally add a namespace so it can be used inside all of views , but I have reasons not to expose my model namespace to them. 幸运的是, 我知道如何全局添加一个名称空间,以便可以在所有视图中使用它 ,但是我有理由不向其公开我的模型名称空间。

Taking that into account, I was thinking of moving the extension methods to a different namespace so I can safely expose it to all my views, but now all the controllers that have access to the model namespace will be missing the extensions. 考虑到这一点,我正在考虑将扩展方法移动到其他名称空间,以便可以将其安全地公开给所有视图,但是现在所有有权访问模型名称空间的控制器都将缺少扩展。 I don't want to add this namespace to all my controllers and this time I don't want to make this namespace globally available. 我不想将此命名空间添加到我的所有控制器中,这一次,我不想使此命名空间全局可用。 I do want the extensions to be usable if just the model namespace is exposed to the code. 我确实希望扩展仅在模型名称空间公开的代码中可用。

The cheap solution would be to add same extension class to two namespaces (in other words two cs files with exact same code) and be done with it, but I would like to use a better solution if possible. 便宜的解决方案是将相同的扩展类添加到两个名称空间(换句话说,两个具有完全相同代码的cs文件)并使用它来完成,但是我想尽可能使用更好的解决方案。

For a moment I thought I can inherit the extension class in another namespace, but that doesn't work since static classes cannot inherit anything. 有一阵子我以为我可以在另一个命名空间中继承扩展类,但这不能工作,因为静态类不能继承任何东西。

I also tried using this solution, but it doesn't work (at least for extension classes). 我也尝试使用解决方案,但它不起作用(至少对于扩展类而言)。 I mean I exposed the namespace that contained only the extension to the views, but my objects in views did not have access to the extension methods. 我的意思是我公开了仅包含视图扩展的名称空间,但是视图中的对象无法访问扩展方法。 I also had to add a dummy class to the namespace (otherwise the app wouldn't even notice the namespace). 我还必须向名称空间添加一个虚拟类(否则应用程序甚至不会注意到名称空间)。

To sum it up, I have an extension class that I need to be available in two different namespaces. 总结起来,我有一个扩展类,需要在两个不同的命名空间中使用它。 Is there some way to achieve this other than copy pasting said class to the other namespace? 除了将上述类复制粘贴到其他名称空间之外,还有其他方法可以实现吗?

Of course, you can't have the same class in two namespaces but you can have the same code produce two classes. 当然,您不能在两个名称空间中使用相同的类 ,但是可以使用相同的代码生成两个类。

One way is to use T4 to generate one file that has both classes. 一种方法是使用T4生成一个同时包含两个类的文件。 (You might not be familiar with T4. If you use Entity Framework, you have it in your project even if you don't know it.) (您可能不熟悉T4。如果使用Entity Framework,即使您不知道它,也可以将它包含在项目中。)

Add a Text Template (.tt) file to your project with a foreach over the namespaces, like the following: 使用命名空间上的foreach将文本模板(.tt)文件添加到您的项目中,如下所示:

<#@ 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();
            }           
        }
    }
}

<#
    }
#>

Or you can convert your .cs file by changing the extension to .tt and setting the CustomTool property to TextTemplatingFileGenerator and the Build Action property to None. 或者,可以通过将扩展名更改为.tt并将CustomTool属性设置为TextTemplatingFileGenerator并将Build Action属性设置为None来转换.cs文件。

One thing you can do is to define the extension method in your main namespace: 您可以做的一件事是在主名称空间中定义扩展方法:

namespace MyNamespace
{
    public interface ISomeInterface { }

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

            return "I did something";
        }
    }
}

And then in the namespaces that you want to expose to your views or controllers, you can wrap with a thin extension that just passes through to your primary one: 然后,在要公开给视图或控制器的名称空间中,可以使用一个瘦扩展进行包装,该扩展将一直传递到主要的扩展:

using MyNamespace;

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

And: 和:

using MyNamespace;

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

This does require that you give the wrapping methods a different name than your primary one, but it leverages your core extension code without having to duplicate it. 这确实需要为包装方法指定与主要方法不同的名称,但是它利用了核心扩展代码而不必重复它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM