【问题标题】:Same extension class available in multiple namespaces多个命名空间中可用的相同扩展类
【发布时间】:2014-08-01 11:39:23
【问题描述】:

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

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

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

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

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

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

总而言之,我有一个扩展类,我需要在两个不同的命名空间中使用它。除了将所述类复制粘贴到另一个命名空间之外,还有其他方法可以实现这一点吗?

【问题讨论】:

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


    【解决方案1】:

    当然,您不能在两个命名空间中拥有相同的类,但您可以让相同的代码产生两个类。

    一种方法是使用 T4 生成一个包含两个类的文件。 (您可能对 T4 不熟悉。如果您使用 Entity Framework,即使您不知道它,也可以在项目中使用它。)

    将一个文本模板 (.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 文件。

    【讨论】:

    • 我终于有时间测试一下这个方法,它就像一个魅力!唯一令人讨厌的部分是那些“可能会损害您的计算机”的警告。我检查了“不再显示”选项,但我有点担心任何外部 tt 文件都会在未经我许可的情况下被执行(并不是我真的希望在我的计算机上遇到任何此类外部文件) .我敢打赌,当我的同事开始编写代码时,这些警告是关于什么的……
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-03-27
      • 1970-01-01
      • 1970-01-01
      • 2012-07-31
      • 2014-09-15
      • 1970-01-01
      • 2023-04-02
      • 2012-01-08
      • 1970-01-01
      相关资源
      最近更新 更多