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
精彩评论