具有不同类型参数的类的抽象类

时间:2016-12-20 12:30:34

标签: c#

我对C#很陌生,我相信类似的问题已经得到了回答,但我不确定要搜索什么,所以问题就在这里:

我有两个类,它们有一些相同的方法和构造函数。但是,这些方法和构造函数接受不同类型的参数(Dictionaries变量是不同的)。那么如何将这些方法和构造函数放入抽象类Brain

Brain.cs

public abstract class Brain
{
    protected int width;
    protected int height;
}

Reward.cs

public class Reward:Brain
{

    public Dictionary<Tuple<Point, Direction>, int> r = 
              new Dictionary<Tuple<Point, Direction>, int>();
    public Reward(int w, int h)
    {
        int directionsCount = Enum.GetNames(typeof(Direction)).Length;
        int direction;
        width = w;
        height = h;
        for (int i = 0; i < w; i++)
            for (int j = 0; j < h; j++)
                for (direction = 0; direction < directionsCount; direction++)
                {
                    Point state = new Point(i, j);
                    r[Tuple.Create(state, (Direction)direction)] = 0;
                }
    }
    public void Set(Point state, Direction direction, int reward)
    {
        r[Tuple.Create(state, direction)] = reward;
    }
    public int Get(Point state, Direction direction)
    {
        return r[Tuple.Create(state, direction)];
    }       
}

Quantity.cs

public class Quantity:Brain
{   
    public Quantity(int w, int h)
    {
         .........
        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++)
                for (direction = 0; direction < directionsCount; direction++)
                {
                    Point state = new Point(i, j);
                    Set(state, (Direction)direction, 0);
                }
    }
    private Dictionary<Tuple<Point, Direction>, decimal> q =
            new Dictionary<Tuple<Point, Direction>, decimal>();         
         .....
    public decimal Get(Point state, Direction action)
    {
        return q[Tuple.Create(state, action)];
    }
    public void Set(Point state, Direction action, decimal value)
    {
        q[Tuple.Create(state, action)] = value;
    }           
}

3 个答案:

答案 0 :(得分:2)

将Brain定义为通用类(https://msdn.microsoft.com/library/sz6zd40f.aspx):

public abstract class Brain<T>
 {
     protected int width;
     protected int height;
     public Dictionary<Tuple<Point, Direction>, T> r = 
                 new Dictionary<Tuple<Point, Direction>, T>();
     public void Set(Point state, Direction direction, T reward)
     {
         r[Tuple.Create(state, direction)] = reward;
     }
     public T Get(Point state, Direction direction)
     {
         return r[Tuple.Create(state, direction)];
     }
 }

而且你可以将你的课程定义为:

public class Reward : Brain<int>
{
}

public class Quantity : Brain<decimal>
{
}

您或许可以将RewardQuantity方法重新定义为基类中的一种方法,它们看起来非常可能,但我不知道,您隐藏的代码中发生了什么背后&#34; ...&#34;

答案 1 :(得分:0)

你可以使用泛型来做到这一点:

"zone.js": "0.7.2"

并声明派生类如下:

npm install

但是这样做的缺点是public abstract class Brain<TValue> // TValue is the generic type parameter { protected int width; protected int height; // use TValue in the declarations public Dictionary<Tuple<Point, Direction>, TValue> r = new Dictionary<Tuple<Point, Direction>, TValue>(); public abstract void Set(Point state, Direction direction, TValue reward); public abstract TValue Get(Point state, Direction direction); } public class Reward : Brain<int> // int is now the generic type argument { public override void Set(Point state, Direction direction, int reward) { r[Tuple.Create(state, direction)] = reward; } public int Get(Point state, Direction direction) { return r[Tuple.Create(state, direction)]; } } public class Quantity : Brain<decimal> { ... } 是完全不同的不变类型。因此,您无法将Brain<int>的实例和Brain<decimal>的实例分配给Reward类型的同一变量:

Quantitiy

因此,如果您只想继承功能或声明,那么通用方法就可以了。但是,如果您希望将Brain<sometype>Brain<int> brain = new Reward(0, 0); // works brain = new Quantitiy(0,0); // fails because Quantity is not a Brain<int> 个实例放在Reward中,则无法使用。

答案 2 :(得分:0)

好吧,我会考虑你的设计的替代品。

继承不应用于代码重用目的,而应用于Is-A关系。最好使用组合:Inheritance (IS-A) vs. Composition (HAS-A) Relationship

public class Brain<T>
{
    private readonly int width;
    private readonly int height;
    private readonly Dictionary<Tuple<Point, Direction>, T> r;

    Brain(int width, int height)
    {
        this.width = width;
        this.height = height;
        .........
        r = new Dictionary<Tuple<Point, Direction>, T>();

        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++)
                foreach (Direction direction in Enum.GetValues(typeof(Direction))
                {
                    var state = new Point(i, j);
                    Set(state, direction, default(T));
                }            
    }

    public void Set(Point state, Direction direction, T reward)
    {
        r[Tuple.Create(state, direction)] = reward;
    }

    public T Get(Point state, Direction direction)
    {
        return r[Tuple.Create(state, direction)];
    }
}

然后其他类将使用组合。例如,对于Reward类:

public class Reward
{
    Reward(int width, int height)
    {
        rewards = new Brain<int>(width, height);

        // Somehow initialize actual rewards here...
        rewards.Set(new Point(5, 8), Direction.Up, 10); // fictif example
    }

    private readonly Brain<int> rewards;
}

因此Brain类基本上管理每个职位的信息。

然后,我可能会考虑是否真的值得拥有多种类型。也许之后的奖励也可能是decimal,特别是如果它们在某个时间点乘以已经decimal的数量。

然而,更好的方法是建立一个代表给定位置和方向的所有信息的类:

public class PositionInfo
{
    public PositionInfo(int reward, decimal quantity)
    {
        Reward = reward;
        Quantity = quantity.
    }

    public int Reward { get; }    // C# 6 - Read-only properties.
    public decimal Quantity { get; }
}

如果许多项目使用默认值且维度很大,您可以考虑使用TryGetValue并仅填充未使用默认值的位置/方向信息。然后修改Get以在项目不在字典中时返回默认信息。事实上,如果所有位置都被填充,那么使用多维数组可能是更好的选择。

我还会添加System.Diagnostics.Debug.Assert之类的验证来帮助在开发过程中发现错误。