Is there a way to use a 'friendy' name for this class/interface?
Asked Answered
J

1

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?

Jezreel answered 18/5, 2018 at 5:51 Comment(5)
I think the best you can do is a using ALIAS = TYPE; statement, but I'd recommend against it since it isn't such a common thing to do so it will make your code harder to follow.Dunant
I'd also need to do that in every single class right? It's quite a large project and I can see how people might get confused when they copy code around and all of a sudden they can't find the 'type' that's actually an alias anywhere.Jezreel
That's correct, which is another downside.Dunant
@john thanks for the suggestion I'll bear it in mind and ask some of my peers what they think.Jezreel
Related question typedef in C#Harriette
I
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.

Incrust answered 18/5, 2018 at 15:19 Comment(5)
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.Jezreel
Well that isn't going to work, the very first problem is C# throws an error that interfaces cannot contain operators :(Jezreel
Changing it to a class also throws an error about casting between a class and an interface. Damn.Jezreel
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<Bar, BarEnum>. That's always the route I went, and it seemed to work out well enough.Incrust
Ok thanks for your time that's what I'm going to do.Jezreel

© 2022 - 2024 — McMap. All rights reserved.