C# 无法通过继承或泛型消除冗余代码

C# 无法通过继承或泛型消除冗余代码,c#,.net,oop,C#,.net,Oop,很抱歉标题含糊不清,但我不知道如何用一句话来概括。我遇到了一个有大量冗余C#代码的情况,看起来使用继承或泛型的某些属性的一些狡猾的技巧可以解决这个问题。然而,我不是一个经验非常丰富的程序员(尤其是使用C#),只是看不到解决方案 简而言之,情况是这样的。我有一堆类,它们都继承自一种类型 public class Foo : SuperFoo { ... public Foo SomeMethod() { ... } } public class Bar : SuperFoo {

很抱歉标题含糊不清,但我不知道如何用一句话来概括。我遇到了一个有大量冗余C#代码的情况,看起来使用继承或泛型的某些属性的一些狡猾的技巧可以解决这个问题。然而,我不是一个经验非常丰富的程序员(尤其是使用C#),只是看不到解决方案

简而言之,情况是这样的。我有一堆类,它们都继承自一种类型

public class Foo : SuperFoo
{
     ...
     public Foo SomeMethod() { ... }
}
public class Bar : SuperFoo
{
     ...
     public Bar SomeMethod() { ... }
}
public class Baz : SuperFoo
{
     ...
     public Baz SomeMethod() { ... }
}
...    
public class SuperFoo
{
     ...
}
当需要处理这些对象的集合时,问题就出现了。我的第一个草案解决方案(糟糕的一个)如下所示:

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();
     }
}
……等等。问题是ProcessX方法中的所有代码基本上都是相同的,不同于正在操作的对象的类型。出于明显的原因,最好将所有这些合并到一个方法中


我的第一个想法是创建一个通用的Process()方法,该方法将
列表
作为参数,然后从那里开始。问题是泛型SuperFoo没有SomeMethod(),并且它不能有一个,因为每个子类的SomeMethod()都有不同的返回类型,所以重写不起作用。

我通常添加一个在基类型上操作的接口

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();
     }
}
当然,这取决于您使用结果的目的


有时,使用泛型可以使它变得更容易,但也可能最终陷入混乱。有时候,在某个地方沮丧更容易。当然,只要你能负担得起,你就会尽量避免这种情况。

下面是一个例子,说明如何使用泛型并使SuperFoo成为一个抽象类

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();
        }
    }
}
公共接口ISuperFoo
{
...
}
公共抽象类SuperFoo,其中T:ISuperFoo
{
公共摘要T somethod();
}
公共类:ISuperFoo
{
...
}
公共类Baz:SuperFoo
{
公共重写返回方法()
{
抛出新的NotImplementedException();
}
}
公共类:ISuperFoo
{
...
}
公共类酒吧:SuperFoo
{
公共重写方法()
{
抛出新的NotImplementedException();
}
}
公共静态类EventHandler
{
公共静态void someEventHashappen(列表)
{
foreach(列表中的SuperFoo项)
{
ISuperFoo结果=item.SomeMethod();
}
}
}
如果需要,您可以用一个具体的类替换ISuperFoo接口,但是您必须转换返回值,这种类型的返回值不符合目的

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();
        }
    }
}
公共抽象类SuperFoo
{
公共摘要T somethod();
}
公共类Foo:SuperFoo
{
公共重写int-SomeMethod()
{
抛出新的NotImplementedException();
}
}
公共静态类EventHandler
{
公共静态void someEventHashappen(列表)
{
foreach(列表中的SuperFoo项)
{
item.SomeMethod();
}
}
}

我看到过这样的代码:返回一个
对象,然后将其转换为适当的类型。虽然这可以解决我在这里介绍的问题,但我应该澄清一下……我不希望
somethod()
返回一个常规
对象,因为
somethod()
在代码的这一部分之外的许多其他地方也被调用,这需要在所有其他地方进行强制转换。谢谢你的建议,谢谢你的回复。但是我对你答案第一部分中的fooreurn和Foo类有点困惑。如果我理解正确,看起来Foo的SomeMethod()的实例将返回一个fooreurn对象,而不是Foo对象。因此,以前在Foo中的所有其他代码现在都应该在FooReturn中,而Foo只需要包含SomeMethod()。如果确实是这样,那么在另一个具有
Foo-foooobject=anotherfoooobject.SomeMethod()的地方,这难道不会破坏代码吗?SomeMethod的返回类型应始终被视为返回ISuperFoo。您会注意到抽象SuperFoo的泛型变量T必须扩展ISuperFoo。这就是提供所需的一致返回类型的原因。我在我的代码中添加了一个Bar示例,希望它能澄清问题。我还将子类从Foo重命名为Baz,希望它能进一步澄清接口、抽象和扩展类型之间的区别。这非常好,可能是我应该想到的!谢谢你的回答。