简体   繁体   中英

Same extension class available in multiple namespaces

In an MVC application I have a namespace that contains specific model class. 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. 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.

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. (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.)

Add a Text Template (.tt) file to your project with a foreach over the namespaces, like the following:

<#@ 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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