page 1 of 1
Comments: 17 | Views: 1283
Dr Herbie
Dr Herbie
Horses for courses
OK, I've been going through some of the newer C# features and I've ended up with an interface and a genericised extension method (with type inference) on the interface.

<BR><BR>public interface IMyInterface<BR>{<BR>    int SomeProperty {get; set;}<BR>    void DoSomething(int);<BR>}<BR><BR>public static class InterfaceExtender<BR>{<BR>    public static T ExtensionMethod<T>(this T implementation, int i) where T : IMyInterface<BR>    {<BR>        implementation.DoSomething(i + implemenatation.SomeProperty);<BR>        return implementation<BR>    }<BR>}<BR><BR>



So now in code you can do

<BR>    IMyInterface item = new InterfaceImplementation();<BR>    item.ExtensionMethod().SomeProperty = 5;<BR>


(note, I'm using a flow syntax in the extension property).


So the question:  are there any benefits to this over just using an abstract class with the extension method built-in?


Herbie
You can scope your extensions in our out eg

namespace Sandbox.ExtensionMethods
{
    class Class1
    {
    }
}

namespace Sandbox.ExtensionMethods.ns2
{
    static class Extension
    {
        public static void Extend2(this Class1 item)
        {
        }
    }
}

namespace Sandbox.ExtensionMethods.ns1
{
    static class Extension
    {
        public static void Extend1(this Class1 item)
        {
        }
    }
}

now putting a using for the namespace to the corresponding extension it will be scoped in

eg

using Sandbox.ExtensionMethods.ns2;

            Class1 item = new Class1();
            item.Extend2();

Or


using Sandbox.ExtensionMethods.ns1;

            Class1 item = new Class1();
            item.Extend1();

not sure where you'd use it tho, Smiley Ant
Sorry,I completely mis-read your question - will be more careful in future,
Ant
TommyCarlier
TommyCarlier
I want my scalps!
I think interfaces are great for defining a "looks like" or "can do" relationship. An abstract base class is great for defining a "is a kind of" relationship. A class can only be derived from 1 base class but can implement multiple interfaces.
stevo_
stevo_
Human after all
http://channel9.msdn.com/forums/TechOff/258761-Wow-extension-methods--interfaces/ you all said I was crazy! (actually you all ignored me Sad)...

But I use this pattern a lot, I think its great.. also using extension methods are interesting because you can obviously still call the methods even on null objects..
stevo_
stevo_
Human after all
Various things, when designing new classes now I tend to cull the 'ugh' properties from interfaces and then let extensions handle them (although I wish they had extension properties as well).. but theres interesting things where you can do really clean systems for attaching values to objects, similar to how the attached properties work by the property value get and set really being routed to the static part of the dependent class.

Mostly I just like how they let you avoid stressing interfaces with senseless 'overloads', you can write them as extension methods instead.. I know in the end these are just calls to helper classes that we could of done before, but the syntax for how they work is so much cleaner I'm much happier using them..

Interesting thing I've seen the null thing used for - lazy patterns.

Edit: The coolest lazy pattern I've seen is in the TPL though, they have a lazyinit class thats a struct (and so implicitely must construct), I thought that was clever..
A good example is providing convenience "overloads".  For example, there's talk about providing a build in service locator interface to the BCL.  One proposal was:
public interface IServiceLocator
{
   object GetInstance(Type type);
   T GetInstance<T>();
   object GetInstance(Type type, string name);
   T GetInstance<T>(string name);
   object[] GetAllInstances(Type type);
   T[] GetAllInstances<T>();
}

That's a lot for a concrete type to define, though, when half the methods will always just defer implementation to the other methods.  Better to use extension methods, here.
public interface IServiceLocator
{
   object GetInstance(Type type);
   object GetInstance(Type type, string name);
   object[] GetAllIntances(Type type);
}


public static class ServiceLocatorExtensions
{
   public static T GetInstance<T>(this IServiceLocator self)
   {
      return (T)self.GetInstance(typeof(T));
   }
   public static T GetInstance<T>(this IServiceLocator self, string name)
   {
      return (T)self.GetInstance(typeof(T), name);
   }
   public static T[] GetAllInstances<T>()
   {
      return self.GetAllInstances(typeof(T)).Cast<T>().ToArray();
   }
}

Wow, Chrome doesn't post the code tags very well.
stevo_
stevo_
Human after all
Yea thats certainly what I use it for most, removing the weight off interfaces (arguably interfaces shouldn't enforce the overloads, but then you have to have the callers all handle overload handling theirself which is beating DRY with a stick and asking for bugs).. the best way then would be to use a utility class to make the call for you, but then that ends up looking weird.. along come extension methods and make it look natural.
this is totally what i hav been looking for. awesome!
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
Calling on null object ... hmm, I must add catches for that ...

Why? Extention methods are intended to look like instance calls, which throw a NullReferenceException if the instance is null:

object o = null;
string f = o.ToString();   // throws a NullReferenceException at runtime, but not because Object::ToString() is checking.

If you use extention methods, then by specifically coding for the null-case you're arguably breaking the semantics:


    IMyInterface item = null
    item.ExtensionMethod().SomeProperty = 5;

is therefore an error at the call-site and not in the method. If you do code around it, be sure to throw a NullReferenceException, but if I were you I'd just leave it in a Debug.Assert() at the top of the method. In fact, if the method returned something at all, it would be breaking the semantics of object-calls.
stevo_
stevo_
Human after all
Sounds right because these are instance calls usually, but in reality they are just static helper classes, what happens if a language calls into them directly which doesn't support extension methods? what if you just call into them directly anyway? I wonder if they wrote any official guidelines for this.
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
instance methods are effectively static methods with the LHS passed as a parameter "this". The reason the NullReferenceException is thrown is because the runtime checks (for virtual methods the hardware does it, for non-virtual ones the runtime does it). It's odd that they chose not to keep this system for extention methods, but in either case you shouldn't be relying on "special-cases" where the LHS is null, because the programmer should guarrantee it at the call site (at worst, Debug.Assert(thisParameter != null) )
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
I just do what I do with regular methods, throw an ArgumentNullException.
stevo_
stevo_
Human after all
Yes but this isn't a CLR feature, its just a feature that the interpreted languages are encouraged to use, vb and c# compiler probably only betray extension methods in CIL because they have attributes on them.. I always think of extension methods as being static helper classes when I'm calling them, despite the fact the compiler is making me think this isn't the case..

Again I think this could go either way, I'd like to see some official advise, otherwise I'm going for the safe option of treating them as static helper methods.

A code example to illustrate in case anyone else following the thread is lost:

var values = Enumerable.Range(1, 10);
var reversed = values.Reverse(); // Normal use case
var alsoReversed = Enumerable.Reverse(values); // Also possible
var ouch = Enumerable.Reverse(null); // What should happen here?

Maybe one day we'll get non-nullable reference types in C# and VB.NET and not have to worry about ArgumentNullExceptions and NullReferenceExceptions any more.

evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }

var ouch = Enumerable.Reverse(null); // What should happen here?

That's fine, it's more the case of

((IEnumerable<int>)null).Reverse() which is the problem. If Reverse is an instance method, it's immediately a NullReferenceException (since "." on anything that is null causes a NullReferenceException), but if it's a static type extention, it'll call "object Reverse(this IEnumerable<T> thisparam)) with thisparam = null, a breach of semantics.

Frankly the compiler and runtime should collude in such a way that useing type-extentions forces an explicit null-check. If you're willing to call it in it's parameterised form Enumerable.Reverse(null) then it's just a null parameter, rather than a null "this" parameter.

@stevo: you can think of all non-virtual and non-interfaced instance methods as static helper functions if you want (that's how they are implemented after all). The fact that "." causes a NullReferenceException is because the runtime provides an explicit check. For fields and virtual methods the check is performed by the hardware, but the principle is the same. Only static helper methods break the semantic of allowing null on the left-hand-side of a ".".

stevo_
stevo_
Human after all
Again my point is that you are talking about a language feature that makes up how the CLR works, extension methods are an abstraction in the written languages.. just happens that the main two languages agreed they both needed to support them.
page 1 of 1
Comments: 17 | Views: 1283
Microsoft Communities