Sorry for the vague title, but I wasn't sure how to summarize this in one phrase. I have a situation with a lot of redundant C# code, and it really looks like some kind of crafty trick using some property of inheritance or generics would solve this. However, I'm not a terribly experienced programmer (particularly with C#) and just can't quite see the solution.
The situation, in simplified form, looks something like this. I have a bunch of classes that all inherit from one type.
public class Foo : SuperFoo
{
...
public Foo SomeMethod() { ... }
}
public class Bar : SuperFoo
{
...
public Bar SomeMethod() { ... }
}
public class Baz : SuperFoo
{
...
public Baz SomeMethod() { ... }
}
...
public class SuperFoo
{
...
}
The problem comes when collections of these objects need to be processed. My first-draft solution (the bad one) looks like this:
public void SomeEventHasHappened(...)
{
ProcessFoos();
ProcessBars();
ProcessBazes();
...
}
public void ProcessFoos()
{
...
foreach (var foo in fooList)
{
...
foo.SomeMethod();
}
}
public void ProcessBars()
{
...
foreach (var bar in barList)
{
...
bar.SomeMethod();
}
}
...and so on. The problem is that basically all of the code in the ProcessX methods is the 开发者_开发百科same, other than the type of the objects that are being operated on. It would be nice to consolidate all of these into one method for obvious reasons.
My first thought was to just make a generic Process() method that took a List<SuperFoo>
as a parameter and just proceed from there. The problem is that a generic SuperFoo does not have a SomeMethod(), and it can't have one because each of the child classes' SomeMethod() has a different return type, so having overrides doesn't work.
I usually add an interface which operates on base types.
interface ISuperFoo
{
public ISuperFoo SomeMethod() { ... }
}
public class Foo : SuperFoo, ISuperFoo
{
// concrete implementation
public Foo SomeMethod() { ... }
// method for generic use, call by base type
public ISuperFoo ISuperFoo.SomeMethod()
{
return SomeMethod();
}
}
public void Processs()
{
...
foreach (var iSuperFoo in list)
{
...
iSuperFoo.SomeMethod();
}
}
Of course it depends what you are using the result for.
Sometimes you can make it easier using generics, but you also can end up in a mess. Sometimes it is just easier to downcast somewhere. Of course, you try to avoid this whenever you can afford it.
Here's an example of how this might work using generics and making SuperFoo an abstract class.
public interface ISuperFoo
{
...
}
public abstract class SuperFoo<T> where T : ISuperFoo
{
public abstract T SomeMethod();
}
public class BazReturn : ISuperFoo
{
...
}
public class Baz: SuperFoo<BazReturn>
{
public override BazReturn SomeMethod()
{
throw new NotImplementedException();
}
}
public class BarReturn : ISuperFoo
{
...
}
public class Bar : SuperFoo<BarReturn>
{
public override BarReturn SomeMethod()
{
throw new NotImplementedException();
}
}
public static class EventHandler
{
public static void SomeEventHasHappened(List<SuperFoo<ISuperFoo>> list)
{
foreach (SuperFoo<ISuperFoo> item in list)
{
ISuperFoo result = item.SomeMethod();
}
}
}
You could replace the ISuperFoo interface with a concrete class if needed, but then you would have to cast the return value which kind of defeats the purpose.
public abstract class SuperFoo<T>
{
public abstract T SomeMethod();
}
public class Foo : SuperFoo<int>
{
public override int SomeMethod()
{
throw new NotImplementedException();
}
}
public static class EventHandler
{
public static void SomeEventHasHappened(List<SuperFoo<int>> list)
{
foreach (SuperFoo<int> item in list)
{
item.SomeMethod();
}
}
}
精彩评论