创建包含要从其子项中使用的常用方法的抽象类

时间:2015-02-10 17:03:35

标签: c# generics

我尝试做的是创建包含从子项中使用的常用方法的抽象类。因为我需要为孩子们​​提供一个静态实例引用,所以我做了类似

的事情
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(例如Scorpion)和仅一只动物,以便我可以用静态实例属性引用它。在实例化之前,任何其他动物都不会被实例化。
  4. 第一个问题是在环境中我需要有一个列表(数组,字典,通用列表......等等)被定义为Animal的列表,然后,填充该列表的沙漠任务将是蝎子和其他人。显然我无法定义具有泛型类型的结构:

    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;
       }
    }
    

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

4 个答案:

答案 0 :(得分:2)

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

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()

使用工厂和/或摆脱单件要求的评论中的建议可能有效,但您已经非常接近您所寻找的。

修改

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

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

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

答案 1 :(得分:1)

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

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>()
    }
}

答案 2 :(得分:0)

这里有很多问题,但首先要了解通用类型协方差和反演:

Return an inherited type from a method

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

答案 3 :(得分:0)

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

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。 : - )