0

Basically I just think the type name is ugly when passing it around my project. I know you can't use an interface that implements the interface because then it's a new interface that just happens to implement the original interface, right?

public class GenericFactory<T, TTypeEnum> : IGenericFactory<T, TTypeEnum>
{
    private readonly IIndex<TTypeEnum, Func<CCompParms, T>> _factory;

    public GenericFactory(IIndex<TTypeEnum, Func<CCompParms, T>> factory)
    {
        _factory = factory;
    }

    public T Create(TTypeEnum serviceType, CCompParms comp)
    {
        return _factory[serviceType](comp);
    }
}

public interface IGenericFactory<T, TTypeEnum>
{
    T Create(TTypeEnum serviceType, CCompParms comp);
}

I have tried:

public interface FriendlyName : IGenericFactory<T, TTypeEnum>
{
}

But when I try to do the following it fails to cast no matter how I cast it.

IGenericFactory<T, TTypeEnum> inter = GetTheInterface();
FriendlyName fn = (inter as FriendlyName);

Is there a way to make the type name friendly?

Jay Croghan
  • 445
  • 3
  • 16

1 Answers1

1

First, any general solution for a "Friendly Name" will still have to be parameterized with both of the generic types, so I don't think that's what you're looking for since it won't really save you any typing.

Assuming you want FriendlyName to already have the types bound, then I think you can get to a workable solution by using Implicit Conversions and the Decorator pattern.

WARNING!!! I just typed this into the browser (no IDE or compiler) and my C# is very rusty, so this will likely need to be tweaked

public interface FooFactory : IGenericFactory<Foo, FooEnum> {

    IGenericFactory<Foo, FooEnum> Wrapped { get; }

    // The "magic" - Note that magic always makes your code harder to understand...

    public static implicit operator FooFactory(IGenericFactory<Foo, FooEnum> wrapped) {
        // I think this can be placed here. If C# won't let you add this
        // implicit operator here, then you can easily implement this factory
        // method as an extension on IGenericFactory<Foo, FooEnum>
        return new FooFactoryWrapper(wrapped);
    }

    public static implicit operator IGenericFactory<Foo, FooEnum>(FooFactory wrapper) {
        return wrapper.Wrapped;
    }

    // I'm pretty sure we can hide this implementation here in the interface,
    // but again, my C# is pretty rusty, so you may have to move this
    // and/or change the visibility
    private class FooFactoryWrapper : FooFactory {

        public IGenericFactory<Foo, FooEnum> Wrapped { get; private set; }

        public FooFactoryWrapper(IGenericFactory<Foo, FooEnum> wrapped) {
            this.wrapped = wrapped;
        }

        // Since the "friendly type" is still an instance of the base type,
        // you'll still have to fully implement that interface. Just delegate
        // all calls to your wrapped type (most useless Decorator ever)

        public Foo Make() { return Wrapped.Make(); } // sample method in IGenericFactory<>
    }
}

Now, you should be able to use it like this:

IGenericFactory<Foo, FooEnum> inter = GetTheInterface();
FooFactory fn = inter; // implicit conversion to wrapper type

DoWork(fn); // use the "friendly name" like it were it's wrapped type
            // implicit conversion back to wrapped type

public void DoWork(IGenericFactory<Foo, FooEnum> fooFactory) {
    ...
}

All that being said, I wouldn't go through this effort. Whenever I've made "Friendly Name" types like this, I then make them part of my "model" and treat them as proper types, which means that I directly ask for them in method signatures and constructors.

Something like this:

public interface BarFactory : IGenericFactory<Bar, BarEnum> { }

// Asking for a BarFactory and not a IGenericFactory<Bar, BarEnum>
public void DoWork(BarFactory barFactory) { ... }

Much less typing and no need for magic.

Matt Klein
  • 7,856
  • 6
  • 45
  • 46
  • 1
    Thanks for the detailed reply, I'll give this a shot. It looks quite promising! I don't really care if people don't understand the magic part, I'm trying to cater for quite junior developers and when they see generics they tend to lose focus and get hung up on them and don't really follow the rest of the code. Some of my devs came from VB6 only recently so the more magic I can do for stuff they don't need to understand the better! A perfect world I'd send them all on more training but that's not an option. – Jay Croghan May 21 '18 at 03:49
  • Well that isn't going to work, the very first problem is C# throws an error that interfaces cannot contain operators :( – Jay Croghan May 21 '18 at 04:34
  • Changing it to a class also throws an error about casting between a class and an interface. Damn. – Jay Croghan May 21 '18 at 04:46
  • 1
    Hmmm.... you could always take the second suggestion and just make a `BarFactory` part of your domain, rather than passing around a bunch of `IGenericFactory`. That's always the route I went, and it seemed to work out well enough. – Matt Klein May 24 '18 at 15:29
  • Ok thanks for your time that's what I'm going to do. – Jay Croghan May 25 '18 at 07:18