开发者

Using Generics in c# in order to avoid code duplication

(Language is c# with VS 2008)

I have the following problem: There are a number of structs (provided as is from 3rd party) that all implement certain methods with the same signatures. I would like to wrap these struct with wrapper classes that implement a certain interface so that these classes can be treated in a uniform way. Example:

interface AnInterface
{
    void DoSomething();
}

struct Struct1
{
    public void DoSomething();
}

class Struct1Wrapper : AnInterface
{
    private Struct1 m_struct;
    public override void DoSomething() // AnInterface implementation
    {
        m_struct.DoSomething();
    }
}

Note that Struct1 DoSomething method is concrete while Struct1Wrapper implements it through an interface for easier handling.

The same goes开发者_运维技巧 with Struct2 and so on - the code of StructXWrapper is the same except for Struct1 replaced by StructX

I have tried using generics in order to avoid code duplication:

class GenericStructWrapper<AStruct> : AnInterface
{
    private AStruct m_struct;

    public override void DoSomething() // AnInterface implementation
    {
        m_struct.DoSomething();
    }
}

But this won't work since the compiler doesn't have a notion about AStruct DoSomething() method.

Any other idea how to implement this without duplicating the code of Struct1Wrapper? Perhaps there is some macro-like feature or some use of reflection?

Thanks,

Ury Jamshy.


You can take a Action<AStruct> in the class constructor that takes the method.

You can then create instances like new GenericStructWrapper<Struct1>(s => s.DoSomething())


C# doesn't safely support structural typing (except in certain unusual contexts), so there's no way to make this completely safe without code-duplication. You either have to go with SLak's technique of asking the client to provide a delegate (will probably involve repeating the same lambda expression over and over) or to assume that the underlying types will satisfy the contract of containing a public void DoSomething() method.

Going with the second option, here's one way using dynamic in C# 4:

public class StructWrapper: AnInterface
{
    private readonly dynamic m_struct;

    public StructWrapper(object myStruct)
    {
        m_struct = myStruct;
    }

    public void DoSomething()
    {
        m_struct.DoSomething();
    }
}

Now, you could try to make this class generic, with the underlying-structure type being the generic-type argument, but that will probably not help you all that much unless you also want to perform structure-specific operations on the wrapped-type. Here's an example of that, with reflection and delegates (C# 3 compatible):

public class StructWrapper<T> : AnInterface where T : struct
{   
    private readonly Action action;

    // deliberately exposed
    public T UnderlyingStruct { get; private set; }

    public StructWrapper(T underlyingStruct)
    {
        UnderlyingStruct = underlyingStruct;
        action = (Action)Delegate.CreateDelegate
                  (typeof(Action), underlyingStruct, "DoSomething");
    }

    public void DoSomething()
    {
        action();
    }
}

Note that you can mix and match the two techniques mentioned above, e.g. reflection but without generics.

Usage:

AnInterface wrapper1 = new StructWrapper(new Struct1());
wrapper1.DoSomething();

StructWrapper<Struct1> wrapper2 = new StructWrapper<Struct1>(new Struct1());
wrapper2.DoSomething();
Struct1 s = wrapper2.UnderlyingStruct; // generics help here
s.SomeOtherMethod();


There is a syntax for this:

class GenericStructWrapper<AStruct> : AnInterface where AStruct : AnInterface
{ 
    private AStruct m_struct; 

    public override void DoSomething() // AnInterface implementation 
    { 
        m_struct.DoSomething(); 
    } 
} 

This says that AStruct must implement AnInterface

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜