创建一个基类方法,根据调用方法

时间:2017-12-25 12:08:25

标签: c# oop inheritance polymorphism

我已经搜索过,但说实话,我真的不知道该找什么。 我有一个名为Item的抽象基类,我将有很多子类,它们都需要在基类中使用方法Split(double amount)。我希望该方法以某种方式知道哪个子类调用它并能够实例化该类型的新对象。 这是我的一个奇怪的游戏,但我需要这个特定的方法将一堆项目分成两个......

!!!基类被称为Item,即使子类将表示项类型和该项类型的数量,有点像某些游戏中的堆栈...... !!!

这是我到目前为止所得到的:

public abstract class Item
{
    public double Quantity { get; private set; }

    public Item()
    {
        Quantity = 1;
    }

    public Item(double quantity)
    {
        Quantity = quantity;
    }

    public bool Merge(Item item)
    {
        if (item.GetType() == GetType())
        {
            Quantity += item.Quantity;
            return true;
        }
        return false;
    }

    public Item Split(double amount, Type häst)
    {
        Quantity -= amount;
        //Here I'd like to do something like "new the-type-that-called-this-method()" 
    }
}

我知道我可以在基类中使用抽象方法,并在每个子类中覆盖它,但是我必须重写基本完全相同的代码我不知道有多少我觉得如果我找不到更好的方法,我想这就是我要做的......

顺便说一句,如果您有任何其他建议,或者您认为我的组织方式是愚蠢的,那么请不要告诉我,我从来没有做过这样的事情,我倾向于过于复杂化事情,简单地让自己因某些原因变得更难......

更好的解释??? 例如,如果我有一个"堆栈" 200个IronOre(让我们说IronOre : Item,并且此实例存储在myIronPile),然后我想将70 IronOre放入新的&{ #34;堆栈&#34 ;.因此,我想致电myOtherIronPile = myIronPile.Split(70)。这将从myIronPile中移除70,并将其放入存储在IronOre中的新myOtherIronPile实例。

任何帮助都非常适用!谢谢! :d

3 个答案:

答案 0 :(得分:0)

要创建给定类型的对象,您可以使用Activator.CreateInstance(来自System.Reflection命名空间):

public Item Split(double amount)
{
    Quantity -= amount;
    return Activator.CreateInstance(GetType(), new object[] { amount }) as Item;
}

GetType是一个虚拟调用,它以最派生的形式返回对象的“真实”类型。

更好的方法是在对派生类型而不是基类Item进行操作时创建泛型方法:

public static T Split<T>(T item, double amount) where T: Item
{
    item.Quantity -= amount;
    return Activator.CreateInstance(typeof(T), new object[] { amount }) as T;
}

然后你就这样使用它:

var myIronPile = new IronOre(200);
var myOtherIronPile = Item.Split(myIronPile, 70);

但要小心在Item变量上使用这些操作,因为这不起作用:

List<Item> items = new List<Item>();
items.Add(new IronOre(200));
var myOtherPile = Item.Split(items[0], 70); // call to Item.Split<Item>(...) !

这会使Activator.CreateInstance抛出异常,因为它想要实例化的类型是抽象的。

List<Item> items = new List<Item>();
items.Add(new IronOre(200));

var myOtherPile = Item.Split(items[0] as IronOre, 70); // works

IronOre item = items[0] as IronOre;
myOtherPile = Item.Split(item, 70); // also works

其他解决方案是将运行时类型与GetType一起使用,这会导致可能无法察觉的性能损失(typeof是编译时构造):

public static T Split<T>(T item, double amount) where T: Item
{
    item.Quantity -= amount;
    return Activator.CreateInstance(item.GetType(), new object[] { amount }) as T;
}

但仍存在一个问题:

List<Item> items = new List<Item>();
items.Add(new IronOre(200));

var myOtherPile = Item.Split(items[0], 70); // myOtherPile is of type Item

IronOre myOtherPile = Item.Split(items[0], 70); // error, cast needed

答案 1 :(得分:0)

首先,Split似乎是您方法的坏名称。当我看到你的方法的名字时,首先想到它的作用是:给定一个项目,它将它分成两个新项目。但这不是它的作用,它实际上改变了给定的项目并将其中的一部分提取到一个新项目中。

嗯... Extract不是更好的名字吗?

public Item Extract(double amount) 

好的,现在当我看到这种方法时,我的第一印象实际上与它的确实相符。

我们也可以使用泛型来改变它,使其尽可能强类型化,如果我们使用静态方法,我们也可以利用类型推断来帮助我们(我们将略微修改名称以使其更加一致它是静态的):

 public static T ExtractFrom<T>(T item, double amount)
    where T: Item
 {
     item.Quantity -= amount;
     return (T)Activator.CreateInstance(
         item.GetType(), new object[] { amount });
 }

你甚至可以考虑将其作为一种扩展方法来实现,尽管如果可能的话我尽量避免改变扩展方法。

请注意,我使用的是item而不是typeof(T)的运行时类型。这很简单,因为类型推断很可能会解析为Item而你会因为无法直接实例化抽象类而得到运行时错误。

答案 2 :(得分:0)

您可以使df['position'] = pd.to_numeric(df['position'], errors='coerce') 类为其所代表的具体In [101]: df['end_position'] = df['position'] + df['ref'].str.len() In [102]: df Out[102]: chr position ref gene_name end_position 0 chr22 24128945 G NaN 24128946 1 chr19 45867080 G ERCC2 45867081 2 chr3 52436341 C BAP1 52436342 3 chr7 151875065 G KMT2C 151875066 4 chr19 1206633 CGGGT STK11 1206638 类型采用类型参数,类似于自我类型。这也有助于Item方法,您可以使用工厂Item方法来简化创建:

Merge

子类必须将自己作为类型参数提供,并且还必须具有无参数构造函数(隐式构造函数很好):

Create

另请注意,此自我类型参数仅限于惯例,是确保子类行为的人。

基于您的示例的示例用法:

public abstract class Item<T> where T : Item<T>, new() {
  public double Quantity { get; private set; }
  public static T Create(double quantity) {
    return new T { Quantity = quantity };
  }
  public void Merge(T item) {
    Quantity += item.Quantity;
  }
  public T Split(double amount) {
    Quantity -= amount;
    return Create(amount);
  }
}

有关此模式及其陷阱的更多信息here