在MVC应用程序中,我有一个包含特定模型类的命名空间。该类实现了一个特定的接口,并且所述接口具有扩展类。
我将扩展类放在与模型类和接口相同的命名空间中,但是,除非我在视图中公开命名空间,否则扩展方法不会在视图中工作。在实际将要使用这些扩展方法的每个视图中通过using
添加命名空间不是一种选择。谢天谢地I know how to globally add a namespace so it can be used inside all of views,但我有理由不将我的模型命名空间公开给他们。
考虑到这一点,我考虑将扩展方法移动到不同的命名空间,以便我可以安全地将它暴露给我的所有视图,但现在所有可以访问模型命名空间的控制器都将缺少扩展。我不想将此命名空间添加到我的所有控制器中,这次我不想让这个命名空间全局可用。如果仅将模型命名空间暴露给代码,我确实希望扩展可用。
廉价的解决方案是将相同的扩展类添加到两个名称空间(换句话说,两个具有完全相同代码的cs文件)并使用它完成,但我想尽可能使用更好的解决方案。
我想我可以继承另一个名称空间中的扩展类,但这不起作用,因为静态类不能继承任何东西。
我也尝试使用this解决方案,但它不起作用(至少对于扩展类)。我的意思是我暴露了仅包含视图扩展名的命名空间,但我在视图中的对象无法访问扩展方法。我还必须在命名空间中添加一个虚拟类(否则应用程序甚至不会注意到命名空间)。
总结一下,我有一个扩展类,我需要在两个不同的命名空间中提供。除了将所述类复制粘贴到另一个名称空间之外,还有其他方法可以实现吗?
答案 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();
}
}
}
这确实要求您为包装方法提供与主要方法不同的名称,但它会利用您的核心扩展代码而无需复制它。