将类看作是用接口定义的

时间:2009-01-22 17:31:05

标签: c# casting interface enumeration

我有100个类,它们有一些相似的元素和一些独特的元素。我创建了一个界面来命名那些相似的项目,例如:interface IAnimal。我通常会做的是:

class dog : IAnimal

但是有100个课程,我不觉得他们全部都在寻找那些可以应用IAnimal的课程。

我想做的是:

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {scruffy as IAnimal, ruffles as IAnimal} // gives null

IAnimal[] animals = new IAnimal[] {(IAnimal)scruffy, (IAnimal)ruffles} //throws exception

然后做

foreach (IAnimal animal in animals)
{
   animal.eat();
}

有没有办法让c#让我把褶边和scruffy作为一个IAnimal而不必写:IAnimal在写这个类时。

谢谢!

编辑(不是懒惰):这些类是从sql存储的proc元数据生成的,这意味着每次生成它时我都必须返回并添加它们,或者修改代码生成器以识别其中的成员接口,实际上这不是一个坏主意。我希望有某种泛型方法或者其他东西。

11 个答案:

答案 0 :(得分:10)

你要求的是鸭子打字而不是C#的一部分我害怕。任何解决方案都将涉及反思和查看属性,我认为手动检查类会更快。

尝试这将是一个有趣的项目。

答案 1 :(得分:6)

你可以用部分类解决这个问题:让机器生成/重新生成的代码放在每个类的一个源文件中,手工编码的部分(从IAnimal定义子类)另一个。

答案 2 :(得分:4)

解决方案是修改代码生成器。目前,它太简单了,无法满足您的需求。如果类中存在相关属性和/或方法,则应添加接口实现。

答案 3 :(得分:4)

你可以创建一个通过反射访问“eat”的适配器,一个穷人的鸭子打字:

public class Adapter<T> : IAnimal
{
   private T x;

   Adapter(T x)
   {
     this.x = x;
   }

   public void eat()
   {
     x.GetType().GetMethod("eat").Invoke(this);
   }
}

然后你可以像这样使用它:

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {new Adapter<dog>(scruffy), new Adapter<cat>(ruffles )};

答案 4 :(得分:1)

假设你真的无法修改cat类,原因很充分,

您可以编写一个继承自IAnimal的cat适配器,即:

  class cat_adapter : IAnimal
  {
       private cat baseCat;
       public cat_adapter( cat aCat)
       {
           baseCat = aCat;
       }

       // Implement IAnimal interface and redirect to baseCat
       public void eat()
       {
            baseCat.munchOnMeowMix();
       }

  }

在C ++中,您可以使用模板,假设您生成的所有类都需要具有相同的函数:

  template <class BaseType>
  class CAnimalAdapter : public IAnimal
  {
  private:
        BaseType* m_baseInstance;
  public:
        CAnimalAdapter(BaseType* baseInstance) :
            m_baseInstance(baseInstance)
        {
        }

        void eat()
        {
            // You will get a compiler error if BaseType doesn't have this implemented
            baseInstance->doEat();                
        }

  }

也许有人比我更喜欢C#-py可以用反射来做同样的事情。

答案 5 :(得分:1)

我不清楚,你可以使用反射进行后期绑定调用,但你最好花时间编辑类或编写宏来执行它。

答案 6 :(得分:1)

如果代码生成器将类生成为partial,则可以添加另一个实现接口的部分定义。

答案 7 :(得分:0)

没有。如果没有具体的基类或有接口,就无法让C#让你这样做。

答案 8 :(得分:0)

如果您已经实现了该方法并且只想实现该接口,则可以在IDE中使用带有replace in files命令的正则表达式。

否则,请看一下扩展方法。它们可能符合您的需求。

答案 9 :(得分:0)

您的类必须实现IAnimal接口。除非它们都是接口/基类的实现,否则两个不同类上的同名方法/属性不被视为等效。

答案 10 :(得分:0)

如果将生成的类实现为部分类,则可以在这些类上实现接口,然后将代码生成器更改为仅生成部分类的一半。这将允许您重新生成类而不会丢失接口实现(或您决定添加的任何其他自定义逻辑)。

这种方法是LINQ to SQL如何生成类文件。