3

As far as I know, C# only let us use extension methods with an instance of a class:

public class MyClass
{
    public static string GetStuff()
    {
        return string.Empty;
    }
}

public static class MyClassExtension
{
    public static string GetOtherStuff(this MyClass myClass)
    {
        return string.Empty;
    }
}

Usage:

MyClass.GetStuff();
MyClass.GetOtherStuff();       // Cannot resolve symbol 'GetOtherStuff'
new MyClass().GetOtherStuff(); // This works

However, I noticed that the MVC framework allows me to extend the HtmlHelpers in such a way that I can use my extension methods without creating any instance of a class. For example, if I create an extension method for HtmlHelper like this:

public static string MyHtmlHelper(this HtmlHelper helper)
{
    return string.Empty;
}

I can use it in a Razor View like this:

@Html.MyHtmlHelper() // no need to instantiate a class

I would really like to achieve the same result with my MyClass, so I can do:

MyClass.GetOtherStuff()

How could I do that?

tocqueville
  • 5,270
  • 2
  • 40
  • 54
  • 15
    What makes you think `@Html` isn't an instance of a class? – James Thorpe May 03 '17 at 09:13
  • Can you please elaborate? How can I achieve that result so I don't have to use the notation new MyClass()? – tocqueville May 03 '17 at 09:15
  • 1
    In a Razor view, `@Html` is [this property](https://msdn.microsoft.com/en-us/library/system.web.mvc.webviewpage.html(v=vs.118).aspx#P:System.Web.Mvc.WebViewPage.Html) of the base class. If you're willing to impose a base-class requirement at the point of usage (as Razor does) then you can achieve this. – Damien_The_Unbeliever May 03 '17 at 09:17
  • 1
    If this is your class can you not just add a static method to it? – Scrobi May 03 '17 at 09:23
  • @Scrobi no because we are building a modular app in which each module should add to the same base class its own methods. – tocqueville May 03 '17 at 10:06
  • @Damien_The_Unbeliever - Please do you have a link that explains your proposed concept – code-assassin May 03 '17 at 10:15

5 Answers5

2

No, you cannot create a C# extension method that does not require an instance of the class. (Here's a longer explanation)

Option #1

However, you can create your extension methods that hang off the existing @Html/HtmlHelper in Razor views.

public static class HtmlHelperExtensions
{
    public static string GetOtherStuff(this HtmlHelper helper)
    {
        return "other stuff";
    }
}

Option #2

It's also possible to create your own equivalent of HtmlHelper, so that you can then access it in just the same way from a .cshtml Razor view.

Define an empty class to extend with your extension methods:

public class MyCustomHelper
{
    // Can just be an empty class.
}

public static class MyCustomHelperExtensions
{
    public string GetStuff(this MyCustomHelper helper)
    {
        return "stuff";
    }
}

public static class MyOtherCustomHelperExtensions
{
    public string GetOtherStuff(this MyCustomHelper helper)
    {
        return "other stuff";
    }
}

The HtmlHelper instance is accessed from a property on WebViewPage.cs. You can extend WebViewPage with your own class and then configure Razor to use that instead:

public class BaseViewPage<TModel> : WebViewPage<TModel>
{
    private MyCustomHelper _foo;

    public MyCustomHelper Foo
    {
        get
        {
            if (_foo == null)
            {
                _foo = new MyCustomHelper();
            }

            return _foo;
        }
        set
        {
            _foo = value;
        }
    }
}

public class BaseViewPage : WebViewPage
{
    private MyCustomHelper _foo;

    public MyCustomHelper Foo
    {
        get
        {
            if (_foo == null)
            {
                _foo = new MyCustomHelper();
            }

            return _foo;
        }
        set
        {
            _foo = value;
        }
    }
}

And then access from a Razor view like this:

<div>
    @Foo.GetOtherStuff()
</div>
Community
  • 1
  • 1
Ben Jenkinson
  • 1,806
  • 1
  • 16
  • 31
  • But I'm not asking how to extend HtmlHelper. If you read my question you'll see that I already did that. I'm asking how to obtain a similar result with my own custom c# class, so that I can add extension methods to it without using the notation `new MyClass()`. I'd like the extension methods to be usable like this: `MyClass.MyExtensionMethod()`. – tocqueville May 03 '17 at 10:09
  • @tocqueville, I'm sorry, but as I said in the first line of my answer, you cannot create an extension method without having an instance of a class _somewhere_. [This answer here](http://stackoverflow.com/a/866932/590382) explains why. You can, however, achieve the same effect from the point-of-view of your Razor views using the "Option #2" I added. – Ben Jenkinson May 03 '17 at 11:50
0

You can use reflection to add static methods to your class. This Stackoverflow answer might give you some idea about using reflection to add methods.

Community
  • 1
  • 1
Vijay
  • 136
  • 4
0

If I understood your question, what about it:

public class Foo {
    public static T Bar<T>(this T obj) where T : class {
        return obj;
    }
}
Lucas Argate
  • 329
  • 2
  • 11
-1

You cannot add static methods to a class via extension methods...

Because it doesn't make sense. What you are proposing is no different that creating a second static class with your new helper method. Just do that.

You want to do this:

public class MyClass
{
    public static string GetStuff()
    {
        return string.Empty;
    }

    // Extension method.
    public static string GetOtherStuff()
    {
        // cannot use any non-public members of MyClass
        return string.Empty;
    }
}
MyClass.GetStuff();
MyClass.GetOtherStuff();

The above is not possible. Also it would give you no advantage over just doing:

public class MyClass
{
    public static string GetStuff()
    {
        return string.Empty;
    }
}

public class MyClassExtension
{
    public static string GetOtherStuff()
    {
       // also cannot use any non-public members of MyClass
        return string.Empty;
    }
}
MyClass.GetStuff();
MyClassExtension.GetOtherStuff();

One final alternative is create a subclass:

public class MyClass
{
    public static string GetStuff()
    {
        return string.Empty;
    }
}

public class MyClassExtension : MyClass
{
    public static string GetOtherStuff()
    {
       // also cannot use any non-public members of MyClass
        return string.Empty;
    }
}
MyClassExtension.GetStuff();
MyClassExtension.GetOtherStuff();
Kempeth
  • 1,856
  • 2
  • 22
  • 37
  • This doesn't answer the question. You're suggesting to create another class while I'm asking how to extend the first one without using the notation `new MyClass() `. There is a specific architectural reason why I need to extend the first class in that way. – tocqueville May 03 '17 at 10:03
  • @tocqueville Yes it does. You cannot add a static extension method. .NET doesn't support it. You can either change `MyClass` normally and get what you desire. Or you can create a second class like in my second example and call `MyClassExtension.GetOtherStuff()`. One final alternative is make `MyClassExtension : MyClass`... – Kempeth May 03 '17 at 10:49
-1

Could you just inherit from the BaseClass in each of your modules:

public abstract class MyBaseClass
{
    public static string SomeProperty { get; set; }

}

//Module 1
public class MyClassOne : MyBaseClass
{
    public static string MyFunction()
    {
        return SomeProperty + "MyClassOne";
    }
}

//Module 2
public class MyClassTwo : MyBaseClass
{
    public static string MyFunction()
    {
        return SomeProperty + "MyClassTwo";
    }
}

This would allow you to do:

MyClassOne.MyFunction() 
Scrobi
  • 1,215
  • 10
  • 13