Andrew Sun
Andrew Sun

Reputation: 4231

Implement IEnumerable<SomeClass> extension method in SomeClass

I have a class like this:

public class SomeClass
{
    public static IEnumerable<SomeClass> GetOutput(IEnumerable<SomeClass> items)
    {
        //Do stuff
    }
}

This class is not static, but I want to make GetOutput an extension method for IEnumerable<SomeClass>. As such, I create a new static class:

public static class SomeClassExtensionMethods
{
    public static IEnumerable<SomeClass> GetOutput(this IEnumerable<SomeClass> items)
    {
        return SomeClass.GetOutput(items);
    }
}

Is there any more elegant way to do this? Why aren't we allowed to make SomeClass.GetOutput an extension method?

Upvotes: 1

Views: 745

Answers (3)

Tom Blodget
Tom Blodget

Reputation: 20772

Why aren't we allowed to make SomeClass.GetOutput an extension method?

You can but not with the standard C# tools.

To the C# compiler, an extension method for a type is a static method that takes an instance of that type as its first parameter and is marked with System.Runtime.CompilerServices.ExtensionAttribute.

When defining an extension method in C#, the C# compiler won't allow the application of that attribute at all, suggesting that you use the this syntax, which does have the cited requirements. So, you could define the SomeClass in some other language or use a tool that adds the attribute after the C# compiler is done.

PostSharp (non-free edition) can do that. Just mark GetOutput with a different attribute and write code to replace it with System.Runtime.CompilerServices.ExtensionAttribute.

public class SomeClass
{
    [ExtensionAspect]
    public static IEnumerable<SomeClass> GetOutput(IEnumerable<SomeClass> items)
    {
        return items;
    }
}

GetOutput is marked with ExtensionAspectAttribute, which is derived from a PostSharp aspect. Post-processing during the build runs the ProvideAspect method, which adds the desired attribute.

[AttributeUsage(AttributeTargets.Method)]
public class ExtensionAspectAttribute : MethodLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        var constructorInfo = typeof (System.Runtime.CompilerServices.ExtensionAttribute).GetConstructor(Type.EmptyTypes);
        var objectConstruction = new ObjectConstruction(constructorInfo);
        var aspectInstance = new CustomAttributeIntroductionAspect(objectConstruction);
        yield return new AspectInstance(targetElement, aspectInstance);

    }
}

So, in another project that references the binary assembly for SomeClass, this works:

var items = new [] { new SomeClass() };
var results = items.GetOutput();

That satisfies the C# compiler, however Intellisense doesn't see it as an extension method and ReSharper colors it as an error.


Of course, this is an academic exercise because there is little reason to not define the extension method in SomeClassExtensionMethods especially since it can be done in the same namespace and even the same .cs file as SomeClass.

Upvotes: 0

Tom Studee
Tom Studee

Reputation: 10452

GetOutput() has to be an instance method, and cannot be static if you wish to extend it.

Upvotes: 1

Mike D
Mike D

Reputation: 61

There is no more elegant way to do this unfortunately.

Why they aren't allowed was already answered here: Why are extension methods only allowed in non-nested, non-generic static class?

Upvotes: 2

Related Questions