Fluent Interface, Need something like global methods in C#

301 views Asked by At

Im currently trying to build a Fluent Interface for a ServiceLocator. To ensure that each the developer can easily setup 1-to-n mappings

I'd like something like this

ServiceLocator.Instance.For<IFoo>(Use<Foo>(), Use<FooBar>());

Singleton is workin fine... the methodsignature for the For method looks like this

public void For<TInterface>(params type[] services)
{
// ... 
}

So I was looking for something like a global method

C# has some global methods, all methods which are defined on System.Object. But when I create a new generic ExtensionMethod on System.Object, the method will not be visible.

public static class MyExtensions
{
  public static void Use<T>(this Object instance)
  {
    // ..
  }
}

MethodChaining would be the alternative, but this approach looks sexy :D

Has anyone an idea?

3

There are 3 answers

3
Andrea On BEST ANSWER

Well, actually when I create an extension method for Object, it is visible. As in,

public static class Extensions
{
    public static void doStuff<T>(this T myObject)
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        int a = 5;
        a.doStuff();

        string b = "aaa";
        b.doStuff();

        List<int> c = new List<int>() { 1, 2, 3, 10 };
        c.doStuff();

        Extensions.doStuff(c);        
    }
}

Did I misunderstand your question?

1
Jamie Ide On

You need to add a using statement for the namespace containing your extension method in order for it to be visible. Adding extension methods to object is rarely a good idea.

EDIT: Okay, now I understand what you're asking. In order to use an extension method you need an instance. You're asking for a static extension method on object (Equals and ReferenceEquals are static methods), and that's not possible. If you define an extension method on object, it will be available on all instances and I'm sure that's not what you want.

public static class ObjectExtensions
{
    public static string TypeFullName(this object obj)
    {
        return obj.GetType().FullName;
    }
}

static void Main(string[] args)
{
    var obj = new object();
    Console.WriteLine(obj.TypeFullName());

    var s = "test";
    Console.WriteLine(s.TypeFullName());
}
1
Bryan Watts On

Service Locator is widely considered to be an anti-pattern. Also, a common registration interface is widely considered to be an unsolvable problem unless you are requiring use of a specific container.

Looking past these two questionable decisions, you can remove the need for the global method by defining overloads of For which accept multiple type arguments:

ServiceLocator.Instance.For<IFoo, Foo, FooBar>();

The For methods would look like this:

public void For<TInterface, TImplementation>()

public void For<TInterface, TImplementation1, TImplementation2>()

...

You have to define an overload for each type count, but it requires the minimal syntax and maximum amount of discoverability. For reference, the .NET Framework's Action and Func types support 9 type arguments.

After writing this out, though, I wonder if I misunderstood the question: why would you specify multiple implementations for the same interface? Wouldn't that lead to ambiguity when resolving IFoo?