【问题标题】:Create abstract classes that contain common methods to be used from their children创建包含要从其子级使用的通用方法的抽象类
【发布时间】:2015-02-11 18:08:07
【问题描述】:

我想要做的是创建抽象类,其中包含要从其子级使用的通用方法。因为我需要为孩子们​​提供一个静态实例引用,所以我正在制作类似

public abstract class Environment<T> where T : Environment<T> {

  private static T s_instance;

  public static T Instance {
    get {
      return (T)s_instance
    }
  }  
}

通过这种方式,如果我要调用一个子对象的 Instance 属性,我将得到子实例,而不是抽象的将子实例声明为:

public Desert : Environment<Desert> { }

如果我这样做了

Desert.Instance

我将获得 Desert 实例及其所有实现和新方法(以及在基础中定义的方法)。
假设我有 2 个这样的课程:环境和动物。
假设我有沙漠和丛林,它们是 2 个环境。
假设我有 2 种动物的蝎子和狮子。

我想做的是从 Environment 访问 Animal 类的一些属性,但对它的实现一无所知。

非常愚蠢的例子:

  1. 我将实例化一个沙漠(一次只存在一个环境)
  2. 沙漠将有一个动物预制列表,可以实例化以匹配那里允许的物种
  3. 一旦实例化,如果没有该类型的动物已经存在,则自动实例化 1(例如蝎子)并且只实例化一个动物,以便我可以使用静态 Instance 属性引用它。在实例化的动物被销毁之前,不会实例化其他动物。

第一个问题是,在环境中,我需要一个列表(数组、字典、通用列表......无论如何),它被定义为动物列表,那么,沙漠的职责就是用这个列表填充该列表蝎子等。显然我不能用泛型类型定义结构:

protected List<Animal<T>> animalsList = new List<Animal<T>> ();


另一件事是:看到在空环境中实例化通用动物的动作很常见,我希望我的通用环境可以检查动物是否已经实例化,如果没有,则实例化一个。问题是因为 Animal 是通用的,我做不到

if (Animal.Instance == null) {
   Instantiate (animalList[Random(0, animalList.Length)]);
}

(请注意前面是伪代码)。

我希望我不会太混乱。也许这是错误的整个想法,也许我不能有泛型,但如果你有任何建议,非常欢迎。 谢谢大家 :-)


编辑:为什么是泛型???
因为我试图创建一个具有通用操作的基类,并且因为我需要对子实例的静态引用,所以我将基类定义为泛型。同样,如果我这样做,则需要仅在基类中声明 Instance 属性,但如果它何时被子类调用,它将返回子类实例。
例子:

public abstract class Environment<T> where T : Environment<T> {

  private static T s_instance;

  public static T Instance {
    get {
      return (T)s_instance
    }
  }

  public int CommonMethod () {
     return 1;
  }
}

public class Desert : Environment<Desert> {

   public int SandStorm () {
      return 12;
   }
}

public class Jungle : Environment<Desert> {

   public int Rain () {
      return 200;
   }
}

在我的控制器中我可以做到

public class Controller () {

   public void CallCommonMethod () {
      Console.Write (Desert.Instance.CommonMethod ());
      Console.Write (Jungle.Instance.CommonMethod ());
   }

   public void CallSandStorm () {
      Console.Write (Desert.Instance.SandStorm ());
   }

   public void CallRain () {
      Console.Write (Jungle.Instance.Rain ());
   }
}

在这种情况下是不允许的

public class Controller () {

   public void CallCommonMethod () {
      Environment.Instance.CommonMethod ();
      // or
      Environment<T>.Instance.CommonMethod ();
      // or similar
   }
}

如果我有

public abstract class Environment {

  public int CommonMethod () {
     return 1;
  }
}

public class Desert : Environment {

   public Desert Instance { get; private set; }

   public Desert () {
      Instance = this;
   }       

   public int SandStorm () {
      return 12;
   }
}

public class Jungle : Environment {

   public Jungle Instance { get; private set; }

   public Jungle () {
      Instance = this;
   }       

   public int Rain () {
      return 200;
   }
}

我需要为每个孩子定义实例。可能我很懒,但我认为通用方式会更好。

【问题讨论】:

  • 您的第一个问题“显然我无法定义具有泛型类型的结构”。这是什么意思?向我们展示不工作的代码,并解释为什么它不工作。
  • 嗨,ShellShock,我编辑了一个示例问题:List> animalList。对此感到抱歉。
  • 我认为你不应该在这里使用单例模式并且有一个动物列表并使用所有动物对象并且只使用动物对象。您的列表也可以包含特定的动物,只需在 Animal 类上实现属性和方法(可能是虚拟的)。
  • 为什么 Animal 类是泛型的?当然泛型类型是环境?因此,您不需要动物的通用列表,但即使您确实创建了一个虚拟属性,该属性将在每个后代类中第一次读取时构造正确的实例。
  • 感谢大家的建议。我只想说我使用泛型来避免需要在每个孩子中定义一个 Instance 属性:如果我有 T Instance 它将返回孩子类型。如果我使用标准的非泛型抽象类,对于每个孩子,我需要通过返回子类型来重新定义 Instance 属性。我只是想为基类中的每个人都拥有一个属性。我希望这对你现在有意义;-)

标签: c# generics


【解决方案1】:

您只需要添加代码即可在抽象泛型基类中创建实例。

public abstract class Environment<T> where T : Environment<T>, new()
{
    private static T _instance = new T();
    public static T Instance
    {
        get { return _instance; } // no need to cast here. It's already of type T.
    }

    public int CommonMethod()
    {
        return 1;
    }
}

public class Desert : Environment<Desert>
{
    public int SandStorm()
    {
        return 12;
    }
}

然后按您的意愿使用。 Desert.Instance.SandStorm()Desert.Instance.CommonMethod()

cmets 中关于使用工厂和/或摆脱单例要求的建议可能是有效的,但您已经非常接近您所寻找的。​​p>

编辑:

您还可以像这样访问静态Instance 属性:

Environment<Desert>.Instance.CommonMethod();
Environment<Desert>.Instance.SandStorm();

但在指定泛型类型之前,您无法获得Instance。所以Environment.Instance 不可用。

【讨论】:

  • 这很酷。非常感谢您。在签署此作为我问题的答案之前,我会尝试一下:-P 再次感谢您
【解决方案2】:

对于你的懒惰问题,你可以做这样的事情

public abstract class Environment
{
    private static Environment instance;

    public static T GetInstance<T>() where T : Environment
    {
        return (T)instance;
    }
}

public class Desert : Environment
{

}

public class class1
{
    public void SomeMethod()
    {
        Environment.GetInstance<Desert>()
    }
}

【讨论】:

  • 确保在某处创建实例和/或在GetInstance 中检查null
  • instance 是如何创建的?如果instance 的类型不正确,则转换将失败。
【解决方案3】:

这里有很多问题,但首先要了解泛型协方差和逆变:

Return an inherited type from a method

这是一个很常见的问题。这是我最近回答的一个链接。

【讨论】:

  • 谢谢伊恩。这非常有用,但它没有回答我的问题。
【解决方案4】:

为了完整起见,这是我的最终解决方案。请注意,有些部分是伪代码。这只是为了让您了解我的想法。

public abstract class Environment<T> where T : Environment<T> {

   private List<Animal> animalList;
   private static T s_instance;

   public static T Instance {
      get {
         return (T)s_instance
      }
   }

   public void ToCallInConstructor () {
      PopulateTheList ();
      if (Animal.Instance == null) {
         Instantiate (animalList.Get (defaultAnimal)); // pseudocode
      }
   }

   public int CommonMethod () {
      return 1;
   }

   public abstract void PopulateTheList();
}

public abstract class Animal {

   public static Animal Instance { get; private set; }

   public Animal () {
      Instance = this;
   }

    public static T GetInstance<T>() where T : Animal {
       return (T)Instance;
    }
}

其他一切都将遵循我在问题的编辑部分中所做的示例,其中我解释了为什么使用泛型。

非常感谢大家的建议,尤其是 Patrick 和 CoderDennis。 :-)

【讨论】:

    猜你喜欢
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多