5

I'm looking at how to solve a problem and I'm not even sure this might be possible at all in C# & .NET 3.5:

Say I have a limited number of interfaces, each describing a specific, non-related set of methods. Now I have a number real-world devices which each may implement just a subset of these interfaces.

During set-up of comms with these devices they will tell me which capabilities they have. I would now like to create an object implementing the interfaces (each resembling one capability of the device) so that higher up in my application architecture I'm able to:

  • write code against the aforementioned interfaces
  • test if that generated object implements a certain interface to see if certain actions are supported

I'm not sure at all which approach to use towards this problem. Any comments or approaches most welcome!

2
  • Firstly, thank you all for your comments and suggestions. Very much appreciated! Ok, I think I should elaborate a bit more on the problem that I'm facing. I have a certain number of capabilities, e.g. CanMakeCoffe, CanCleanKitchen, etc. There are some capabilities that most devices will implement, e.g. CanMakeCoffee. What I would like to avoid is to define somewhere in the source code classes for these device as in CDeviceOne : ICanMakeCoffee, ICanCleanKitchen CDeviceTwo : ICanMakeCoffee Commented Nov 3, 2009 at 15:23
  • I'd rather have the device tell me when they connect what they can do and I'd then create an object that resembles their abilities. Does that make any sense? Commented Nov 3, 2009 at 15:23

6 Answers 6

5

Use a mocking framework such as Moq, RhinoMocks or TypeMock Isolator

If you're looking to do something lower level, things like Castle DynamicProxy might be a good direction for you.

Sign up to request clarification or add additional context in comments.

3 Comments

A search for duck typing might also yield results.
@leppie: Very good point. @Timo: If you use a dynamic language such as IronPython or IronRuby (or dynamic related stuff in C# 4), you might be able to achieve something useful (though you wouldnt be using actual interface defintions and is or as in the implementation
@leppie: thanks for your suggestion. I already had a look at duck typing but I wasn't sure if it would help me with the problem. I'll take another look anyways! @Ruben: thanks for your pointers to the DynamicProxy. Most interesting! I'll also have a closer look there.
3

Try something like LinFu.DynamicObject.

2 Comments

Very interesting indeed. I especially like the idea of creating a mixin. I'm just a bit hesitant to use that kind of framework for production code... I'll have to look at the license. Anyways thanks for that!
It's licensed as LGPL. And you should thank Philip, not me :)
1

Maybe you don't need to make this so "dynamic".

Have you checked the Abstract Factory pattern? It seems that basically what you need is to create a concrete implementation for each of your interfaces based on a device type.

You don't need to have a single class implementing lots of interfaces, it is enough to have appropriate implementation of the specific interface when your code requests it.

Each concrete implementation of your abstract factory can generate several interface implementations based on your device type.

Example:

 public interface IDeviceFactory
 {
      ISomething GetSomeInterface();
      ISomethingElse GetSomeOtherInterface();
 }

and then you implement the specific factory for each device:

public class SimpleDeviceFactory : IDeviceFactory
{
     public virtual ISomething GetSomeInterface()
     { return Something.Empty; }

     public virtual ISomethingElse GetSomeOtherInterface()
     { return new SomeSimpleConreteImplementation(); }
}

or maybe:

public class ComplexDeviceFactory : IDeviceFactory
{
     public virtual ISomething GetSomeInterface()
     { return new ComplexStuff(); }

     public virtual ISomethingElse GetSomeOtherInterface()
     { return new EvenMoreComplexStuff(); }
}

And then, finally, you create the right factory for your device:

public class DeviceFactory
{
     public static IDeviceFactory CreateForDevice(IDevice device)
     {
          DeviceType type = device.Type; // or something like this
          switch (type)
          {
              case DeviceType.Simple: 
                 return new SimpleDeviceFactory();

              case DeviceType.Complex: 
                 return new ComplexDeviceFactory();

              default:
                 throw new NotImplementedException();
          }
     }
}

Note that I have also marked IDeviceFactory method implementations as virtual, so that you can easily reuse or override specific interfaces for a specific device.

1 Comment

Thanks Groo, that is really a straightforward approach to the problem! As I said in my comment on my original question I would like to avoid to make the code "device centric" (create classes for every possible device) and rather have an object created based on the feedback from the device (what it is able to do).
0

It is possible, just not easy. You need to make a string which is basically a source file and then create and use a CSharpCodeProvider, which you then order to compile your code. If it works, you can manually access your created objects through reflection.

For the interested, i did it a while back, the details are a bit foggy.

1 Comment

It would probably be as easy to emit il-code into a dynamic assembly in memory. However, a mocking framework could do this easier/in less code. ;)
0

.NET 4 might make it easier, you could use one of the already mentioned framework or go the System.Reflection route. You'll find plenty of samples on the internet.

I've done both in the past. Rolling my own il.Emit stuff and using a framework (Spring.NET in my case). For anything but the trivial stuff, use one of the frameworks.

Comments

0

You can also try with the Re-mix project. One of the main features of this project is create mixins, that lets you add interfaces with implementations and state to other classes. Take a look this example:

using Remotion.Mixins;
using Remotion.TypePipe;
//...

public interface ITargetInterface
{
    void DoSomething();
}
// . . .
public class TargetImplementation : ITargetInterface
{
    public void DoSomething()
    {
        Console.WriteLine("ITargetInterface.DoSomething()");
    }
}
// . . .
public interface IMixinInterfaceA
{
    void MethodA();
}
// . . .
public class MixinImplementationA : IMixinInterfaceA
{
    public void MethodA()
    {
        Console.WriteLine("IMixinInterfaceA.MethodA()");
    }
}
// . . .
public interface IMixinInterfaceB
{
    void MethodB(int parameter);
}

// . . .
public class MixinImplementationB : IMixinInterfaceB
{
    public void MethodB(int parameter)
    {
        Console.WriteLine("IMixinInterfaceB.MethodB({0})", parameter);
    }
}

Then you can merge those types to create a mixin:

var config = MixinConfiguration.BuildFromActive()
            .ForClass<TargetImplementation>()
            .AddMixin<MixinImplementationA>()
            .AddMixin<MixinImplementationB>()
            .BuildConfiguration();
MixinConfiguration.SetActiveConfiguration(config);

Unfortunately, you cannot simply call new on the TargetImplementation and expect a mixin. Instead, you have to ask Re-mix to create a TargetImplementation instance so that it can build a new type to your specification and instantiate it. When it is asked for an instance of TargetImplementation, it will return a mixin containing all of the interfaces and classes combined.

ITargetInterface target = ObjectFactory.Create<TargetImplementation>(ParamList.Empty);

target.DoSomething();

var targetAsMixinA = target as IMixinInterfaceA;
if (targetAsMixinA != null)
{
   targetAsMixinA.MethodA();
}

var targetAsMixinB = target as IMixinInterfaceB;
if (targetAsMixinB != null)
{
    targetAsMixinB.MethodB(30);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.