0

I have three assemblies, A.dll, B.dll, C.dll that all define a single namespace A, B, C and a single class A, B, C.

The classes in each assembly have the exact same API, identical in every way.

I now need to write an application that uses all three assemblies and I am struggling to find the best way to do this.

For example the classes define the following function:

string GetName();

In my application I have a matching function, but how can I simplify the implementation?

A MyA = new A();
B MyB = null;
C MyC = null;

public string GetName() {
  if (MyA != null) return MyA.GetName();
  else if (MyB != null) return MyB.GetName();
  else if (MyC != null) return MyC.GetName();
}

I have a lot of functions in this API so it would be messy to do this if/else over and over again.

Interfaces

I thought about defining an interface for the API, but I don't want to add another assembly that my application and these three assemblies are dependent on. I also don't want to create an inter-dependency between any of these assemblies. This is because the assemblies are used individually in other situations that unfortunately only allow for a single assembly, which is out of my control.

Reflection

I thought about using reflection and delegates:

private void GetAPI() {
    var Api = MyA;
    Type t = Api.GetType();
    System.Reflection.MethodInfo m = t.GetMethod("GetName");
    _GetName = (GetNameDelegate)Delegate.CreateDelegate(typeof(GetNameDelegate), Api, m);
}

public string GetName() {
    return _GetName();
}

This works, but how do I expand this to re-use this piece of code for all three assemblies? I.e. how to pass in MyA, MyB, MyC into the GetAPI function?

Thanks!

Andy
  • 938
  • 1
  • 10
  • 21
  • Have a look at https://stackoverflow.com/questions/6802573/c-sharp-interfaces-whats-the-point – Mick Jul 25 '17 at 08:29
  • Describes interfaces, which are the natural solution here, but where would I define the interface? – Andy Jul 25 '17 at 08:36
  • 1
    You would need to define an interface in a class library and then create a project reference to that class library from each class library wishing to implement the interface – Mick Jul 25 '17 at 08:38
  • _"exact same API, identical in every way"_ - not really. They may be equivalent but the identity is namespace+name, and you made those very different. – H H Jul 25 '17 at 08:38
  • 2
    _I don't want to add another assembly_ is of course the illogical stumbling block. Why not, it is the simplest and easiest solution. – H H Jul 25 '17 at 08:40
  • Henk - yes, but you understand what I meant - the functions in the classes are identical. That is the important aspect here. – Andy Jul 25 '17 at 08:41
  • I don't think you have many choices(without creating a shared interface) here to simplify the code since maybe you have the same name of api in different assembly but there are different in result – BRAHIM Kamel Jul 25 '17 at 08:41
  • Henk - these assemblies are used in other situations that unfortunately have limitations imposed. I am looking for a more complicated and less easy solution than using another assembly and is better than what I am currently doing. – Andy Jul 25 '17 at 08:46
  • 1
    In your reflection example, couldn't you declare variable _Api_ as _object_ (rather than _var_) and assign an instance of the required class type - then get delegates for each method that you need. – PaulF Jul 25 '17 at 09:35

2 Answers2

1

I suggest to create an Interface. And use the interface instead of the actual class. Another way is to create and an Abstact Class and ovverrid all the function for each class of yours

llouk
  • 513
  • 4
  • 15
  • Where do I define the interface or abstract class? Note that I put in my question that I didn't want to add another assembly to the mix. Thanks. – Andy Jul 25 '17 at 08:23
  • Are those dll's yours? Or the code is someone else's? What is the reason for not wanting to add your own code somewhere? – llouk Jul 25 '17 at 09:07
  • My assemblies but they used in third-party situations I don't control where there are limitations. – Andy Jul 25 '17 at 09:08
1

Assuming you can't go about this using standard OOP patterns (interface, inheritance), you could make some helper methods to avoid writing lots of code to invoke your delegates. For example, these methods below allow you to do expressions like this on your Api classes:

var nameForApiA = Wrapper.Invoke<ApiA, string>(apiA => apiA.GetName());

Note that this calls Activator.CreateInstance on the type parameter, so if your API classes have constructor parameters, those will need to be handled another way.

public class Wrapper
{
    public static void Invoke<TApi>(Action<TApi> method)
    {
        var instance = Activator.CreateInstance<TApi>();
        method.Invoke(instance);
    }

    public static TReturn Invoke<TApi, TReturn> (Expression<Func<TApi, TReturn>> method)
    {
        var instance = Activator.CreateInstance<TApi>();
        Func<TApi, TReturn> compiled = method.Compile();
        return compiled(instance);
    }
}
Peter
  • 674
  • 6
  • 14