Implementing command pattern and polymorphism - c#

I want to implement a command pattern. I have the following:
public class State
{
public int Number { get; set; }
public void Execute(IAction action)
{
if (action.IsValid(this))
action.Apply(this);
}
}
public interface IAction
{
bool IsValid(State state);
void Apply(State state);
}
public class ActionSet5IfZero : IAction
{
public bool IsValid(State state)
{
if (state.Number == 0)
return true;
else
return false;
}
public void Apply(State state)
{
state.Number = 5;
}
}
And the program:
static void Main(string[] args)
{
State s = new State();
s.Execute(new ActionSet5IfZero());
}
That works as expected. My problem begins, when I would like to extend the State class:
public class ExtendedState : State
{
public int Number2 { get; set; }
}
Now the action must apply changes on ExtendedState. So I thought I would create extended action that has two additional functions that take ExtendedState as a parameter:
public class ExtendedActionSet5IfZero : IAction
{
public bool IsValid(State state)
{
throw new NotImplementedException();
}
public void Apply(State state)
{
throw new NotImplementedException();
}
public bool IsValid(ExtendedState state)
{
if (state.Number == 0 && state.Number2 == 0)
return true;
else
return false;
}
public void Apply(ExtendedState state)
{
state.Number = 5;
state.Number2 = 5;
}
}
This is something I already do not like because the functions that implement the interface become redundant. Moreover I need to create a new Execute function in my ExtendedState that utilizes the new type and not IAction (otherwise not implemented functions get called).
I am sure it can be done in a nice OO way. Can you help me out? The aim is to create an extensible State class and IAction interface (maybe even generic, I do not know), so I can extend the State but remain the generic functionality without additional coding.

You could add a virtual SetNumber method to state
public class State
{
public int Number { get; set; }
public virtual void SetNumber(int n)
{
Number = n;
}
public void Execute(IAction action)
{
if (action.IsValid(this))
action.Apply(this);
}
}
In the extended state you orverride it
public class ExtendedState : State {
public int Number2 { get; set; }
public orverride void SetNumber(int n)
{
base.SetNumber(n);
Number2 = n;
}
}
The action would then be implemented like this
public void Apply(State state)
{
state.SetNumber(5);
}
EDIT:
What about declaring Number as array?
public class State
{
public int[] Numbers { get; private set; }
public State()
{
Numbers = new int[1];
}
...
}
The action then does this
public void Apply(State state)
{
for (int i = 0; i < state.Numbers.Length; i++) {
state.Numbers[i] = 5;
}
}
The constructor of ExtendedState would initialize Numbers with
Numbers = new int[2];
In addition, you could have properties for the single numbers
public int Number {
get { return Numbers[0]; }
set { Numbers[0] = value; }
}
and
public int Number2 {
get { return Numbers[1]; }
set { Numbers[1] = value; }
}

You could use generics:
interface IAction<TState> where TState: State
{
bool IsValid(TState state);
void Apply(TState state);
}

How about adding StateContainer to State and Action:
public interface IStateContainer<TState, TAction> where TState : IState where TAction : IAction<TState> {
public TState State;
public void Execute(TAction action);
}
public interface IState { }
public interface IAction<TState> where TState : IState {
bool IsValid(TState state);
void Apply(TState state);
}
Then your original classes can be replaced with:
public class ValidatingStateContainer<TState, TAction> : IStateContainer<TState, TAction> {
public ValidatingStateContainer(TState state) {
State = state;
}
public TState State { get; private set; }
public void Execute(TAction action)
{
if (action.IsValid(this))
action.Apply(State);
}
}
public class ActionSet5IfZero : IAction<NumberState>
{
public boolean IsValid(NumberState state)
{
if (state.Number == 0)
return true;
else
return false;
}
public void Apply(NumberState state)
{
state.Number = 5;
}
}
public class ExtendedActionSet5IfZero : ActionSet5IfZero, IAction<TwoNumberState>
{
public boolean IsValid(TwoNumberState state)
{
if (base.IsValid(state) && state.Number2 == 0)
return true;
else
return false;
}
public void Apply(TwoNumberState state)
{
base.Apply(state);
state.Number2 = 5;
}
}
public class NumberState : IState {
public int Number { get; set; }
}
public class TwoNumberState : NumberState {
public int Number2 { get; set; }
}

Related

Add subtype objects to list of supertype, then return list of subtypes from list of supertypes

I have 3 interfaces.
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
IEquipable is implemented by the classes Helmet and Bow, and IConsumable is implemented by classes Potion and Food.
Then, I have a class with a property which contains a List of IItem, and proceed to add a few items of both IEquipable and IConsumable after instantiating it.
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Program.cs
...
Character char = new Character();
char.AddItem(new Potion());
char.AddItem(new Food());
char.AddItem(new Helmet());
char.AddItem(new Bow());
...
Is there a way I can get a List of all IEquipable members from the List of IItems, each AS IEquipable?
I want to do something like
...
List<IEquipable> equipmentList = //do something to char.Items and get all items of type IEquipable.
IEquipment equipment = equipmentList.First(...)
equipment.Equip();
...
I've tried using List<IEquipable> equipmentList = char.Items.OfType<IEquipable>().ToList() but the resulting list ends up empty.
I implemented (and fixed minor typos in) your code like this:
void Main()
{
Character character = new Character();
character.AddItem(new Potion());
character.AddItem(new Food());
character.AddItem(new Helmet());
character.AddItem(new Bow());
List<IEquipable> equipmentList = character.Items.OfType<IEquipable>().ToList();
}
public class Potion : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Food : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Helmet : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public class Bow : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Your exact code (albeit char renamed to character) works perfectly fine. The equipmentList ends up with two elements. The issue you're seeing, i.e. "the resulting list ends up empty", is not reproducible with the code you've posted.
You can use the OfType method
Filters the elements of an IEnumerable based on a specified type.
Signature
public static IEnumerable<TResult> OfType<TResult> (this IEnumerable source)
Usage
var equipable = Character.Items.OfType<IEquipable>();
Or encapsulate it as a method in the instance or an extension method if you like
So it does work like I wanted. My actual code just had another issue and I'm a dummy for not actually posting that. So here it is, for future reference.
using System.Collections.Generic;
using RolePlayGame.Library.Items.Backstage;
using System.Linq;
using System.Text;
using System;
namespace RolePlayGame.Library.Characters.Backstage
{
public class Inventory
{
public List<IItem> StoredItems { get; private set; }
public List<EquippedItem> Gear { get; private set; }
public Inventory()
{
this.StoredItems = new List<IItem>();
this.Gear = new List<EquippedItem>();
}
public bool HasItem(string name)
{
return this.StoredItems.Exists(item => item.Name == name);
}
public bool HasItem(IItem item)
{
return this.StoredItems.Contains(item);
}
public void RemoveItem(string name)
{
int firstIndex = this.StoredItems.FindIndex(item => item.Name == name);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void RemoveItem(IItem item)
{
int firstIndex = this.StoredItems.IndexOf(item);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void AddItem(IItem item, int quantity)
{
for (int i = 0; i < quantity; i++)
{
this.StoredItems.Add(item);
}
}
public void AddItem(IItem item)
{
this.StoredItems.Add(item);
}
public bool CheckEquipmentSlot(EquipmentSlot slot)
{
return this.Gear.Exists(item => item.UsedSlots.Contains(slot));
}
public bool HasEquipment(IEquipment equipment)
{
return this.Gear.Exists(item => item.Item == equipment);
}
public void AddEquipment(IEquipment equipment)
{
IEquipment alreadyEquipped;
foreach (EquipmentSlot slot in equipment.SlotsUsed)
{
if (this.Gear.Exists(item => item.UsedSlots.Contains(slot)))
{
alreadyEquipped = this.Gear.Find(item => item.UsedSlots.Contains(slot)).Item;
this.RemoveEquipment(slot);
this.StoredItems.Add(alreadyEquipped);
}
}
EquippedItem newEquipment = new EquippedItem(equipment);
this.Gear.Add(newEquipment);
}
public void RemoveEquipment(EquipmentSlot slot)
{
this.Gear.RemoveAll(equipment => equipment.UsedSlots.Contains(slot));
}
public int GetAttributeBonusTotal(AttributeType attribute)
{
int bonusTotal = 0;
foreach (IEquipment item in this.StoredItems.OfType<IEquipment>().ToList())
{
bonusTotal += item.GetAttributeBonus(attribute);
}
return bonusTotal;
}
public int GetCarryWeight()
{
int totalWeight = 0;
foreach (IItem item in StoredItems)
{
totalWeight += item.Weight;
}
return totalWeight;
}
public string GearToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Equipped Gear:");
foreach (EquippedItem equipment in this.Gear)
{
builder.Append($"\n {equipment.Item.Name}");
}
return builder.ToString();
}
public string ItemsToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Inventory:");
foreach (IItem item in this.StoredItems.Distinct())
{
builder.Append($"\n {item.Name} x {this.StoredItems.FindAll(value => value == item).Count()}");
}
return builder.ToString();
}
public int GetDefenseRateAgainstTypeTotal(DamageType againstType)
{
int rate = 0;
List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList();
foreach (IOutfit item in outfits)
{
rate += item.GetDefenseRateAgainstType(againstType);
}
return rate;
}
}
}
One of the last lines has the problem (now fixed). List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList(); used to be List<IOutfit> outfits = this.Gear.OfType<IOutfit>().ToList();. But Gear is of type List<EquippedItem>, and EquippedItem is not an implementation of IItem.
Here is EquippedItem.cs
using RolePlayGame.Library.Items.Backstage;
using System.Collections.Generic;
namespace RolePlayGame.Library
{
public class EquippedItem
{
public List<EquipmentSlot> UsedSlots { get; set; }
public IEquipment Item { get; set; }
public EquippedItem(IEquipment equipment)
{
this.Item = equipment;
this.UsedSlots = equipment.SlotsUsed;
}
}
}
I needed to select the Item property from the items inside Gear as another list before doing the type filtering with .OfType<IOutfit>(). That's where .Select(value => value.Item) enters the stage.
So that's that. I'll learn to post actual code for future questions.

Polymorphism and Interfaces in C#

Create three small classes unrelated by inheritance—classes Building, Car and Bicycle. Write an interface ICarbonFootprint with a GetCarbonFootprint method. Have each of your classes implement that interface, so that its GetCarbonFootprint method calculates an appropriate carbon footprint for that class (check out a few websites that explain how to calculate carbon footprints). Write an app that creates objects of each of the three classes, places references to those objects in List, then iterates through the List, polymorphically invoking each object’s GetCarbonFootprint method. Constructor of Car initialize “gallon of gas”, and the Building constructor will initialize buiding-square-footage.
how to calculate carbon-footprint
One gallon of gas yields 20 pounds of CO2 for a car
Multiply the square footage by 50 for a building
None for a bicycle
My instructor's code:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
static void Main(string[] args)
{
Bicycle bike = new Bicycle();
Building b = new Building();
Car car = new Car();
List<ICarbonFootprint> list = new List<ICarbonFootprint>();
list.Add(bike);
list.Add(b);
list.Add(car);
int totalCarbon = 0;
foreach (var item in list)
{
totalCarbon += item.GetCarbonFootprint();
Console.WriteLine("{0} has a footprint of: {1}", item, item.GetCarbonFootprint());
}
Console.WriteLine("Total footprint is: {0}", totalCarbon);
Console.ReadKey();
}
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
Me integrating my instructor's code (lines 12-23 changed AKA class Program was the only thing changed):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
So, replacing my code for class Program with my instructor's code, I received the following errors:
Program.cs(51,23,51,41): error CS1729: 'Miller.Building' does not contain a constructor that takes 1 arguments
Program.cs(52,23,52,34): error CS1729: 'Miller.Car' does not contain a constructor that takes 1 arguments
Now, because the last two days before Spring break were cancelled due to the weather (snow), we weren't able to discuss. My code seems to do what the directions ask, but I would like to get my instructor's code for class Program working with my code. Could someone help me with these errors possibly?
There are a few issues with your code.
First up you need to include the constructors to make the code compile.
For Building this would look like:
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
And for Car this would look like:
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
Next, you're not following the rules for calculating the carbon footprint.
They should be:
//Bicycle
public int GetCarbonFootprint()
{
return 0;
}
//Building
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
//Car
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
Finally, your instructor's code doesn't actually display any results. The code in the for loop should be changed to be Console.WriteLine(list[i].GetCarbonFootprint()); if this is a console app.
So, all up the code should look like this:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
Console.WriteLine(list[i].GetCarbonFootprint());
}
public class Bicycle : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 0;
}
}
public class Building : ICarbonFootprint
{
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
public string Address { get; set; }
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
}
public class Car : ICarbonFootprint
{
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
I've opted to short-cut the property definitions rather than implement them with fields.
The output is:
0
125000
200
You should write constructors for Building and Car like next:
public Building(int MyValue)
{
...
}
and your code will work fine.
Suggestion: Car and Bicycle shares properties, and the ICarbonFootprint implementation, so you can create a base class with an abstract method. Also the GetCarbonFootprint from ICarbonFootprint interface must be type of System.Double.
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
public class Building : ICarbonFootprint
{
public int BuildingSquareFootage { get; set; }
public string Address { get; set; }
public Building(int buildingSquareFootage, string address)
{
BuildingSquareFootage = buildingSquareFootage;
Address = address;
}
public int GetCarbonFootprint()
{
return BuildingSquareFootage * 50;
}
public override string ToString()
{
return string.Format("Building");
}
}
public abstract class CarBicycleBase : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
protected CarBicycleBase(string make, string model)
{
Make = make;
Model = model;
}
public abstract int GetCarbonFootprint();
}
public class Bicycle : CarBicycleBase
{
public Bicycle(string make, string model)
: base(make, model) { }
public override int GetCarbonFootprint()
{
return 0;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Car : CarBicycleBase
{
public int GallonOfGas { get; set; }
public Car(int gallonOfGas, string make, string model)
: base(make, model)
{
GallonOfGas = gallonOfGas;
}
public override int GetCarbonFootprint()
{
return GallonOfGas * 20;
}
public override string ToString()
{
return string.Format("Car");
}
}
Example:
...
var list = new List<ICarbonFootprint>(3)
{
new Car(10, "...", "..."),
new Bicycle("...", "..."),
new Building(20, "...")
};
foreach (ICarbonFootprint item in list)
item.GetCarbonFootprint();
...
I hope it helps.

Avoid having to cast with generics and a list of custom data

I have the following code for supporting a list of different types :
public enum eType
{
tInt,
tString,
tDateTime
}
public interface ICustomType<out T>
{
T Value { get; }
}
public abstract class DifferentType
{
protected DifferentType(eType type, string mnemonic)
{
Type = type;
Mnemonic = mnemonic;
}
public string Mnemonic { get; private set; }
public eType Type { get; private set; }
}
public class DateTimeType : DifferentType, ICustomType<DateTime>
{
public DateTimeType(DateTime value, string mnemonic)
: base(eType.tDateTime, mnemonic)
{
Value = value;
}
public DateTime Value { get; private set; }
}
public class IntType : DifferentType, ICustomType<int>
{
public IntType(int value, string mnemonic)
: base(eType.tInt, mnemonic)
{
Value = value;
}
public int Value { get; private set; }
}
public class StringType : DifferentType, ICustomType<string>
{
public StringType(string value, string mnemonic)
: base(eType.tString, mnemonic)
{
Value = value;
}
public string Value { get; private set; }
}
public static class UtilValue
{
public static T GetValue<T>(DifferentType customType)
{
return ((ICustomType<T>)customType).Value;
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { GetInt(), GetString(), GetDate() };
foreach (var i in values)
{
switch (i.Type)
{
case eType.tInt:
int resInt = UtilValue.GetValue<int>(i);
break;
case eType.tString:
string resString = UtilValue.GetValue<string>(i);
break;
case eType.tDateTime:
DateTime resDateTime = UtilValue.GetValue<DateTime>(i);
break;
}
}
}
private DateTimeType GetDate()
{
return new DateTimeType(new DateTime(2000, 1, 1), "MnemonicDate");
}
private IntType GetInt()
{
return new IntType(5, "MnemonicInt");
}
private StringType GetString()
{
return new StringType("ok", "MnemonicString");
}
}
and would like to avoid the cast at line return ((ICustomType<T>)customType).Value; in the UtilValue class, any idea how I can get rid of that while still keeping the design?
I am not even sure if this cast is expensive to do? My guess is most certainly.
Visitor-pattern example:
interface IDifferentTypeVisitor
{
void Visit(DateTimeType dt);
void Visit(StringType st);
}
class DifferentType
{
public abstract void Accept(IDifferentTypeVisitor visitor);
}
class DateTimeType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class StringType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class SomeVisitor : IDifferentTypeVisitor
{
public void Visit(DateTimeType dt)
{
//DateTime resDateTime = dt.Value; Or similar
}
public void Visit(StringType st)
{
//string resString = st.Value; Or similar
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { /* Content */ };
var visitor = new SomeVisitor();
foreach (var i in values)
{
i.Accept(visitor);
}
}
}
In C# 4 with dynamic it's possible to save some code by adding this to DifferentType:
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit((dynamic)this);
}
and then delete all other Accept methods. It hurts performance but it looks better ;-)

ProtoBuf - Migration to new version

I recently migrated to new version of protobuf-net, and i started getting this error message after
Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a subclass
Call Stack Trace
protobuf-net.dll!ProtoBuf.Meta.MetaType.AddSubType(int fieldNumber = 1, System.Type derivedType = {Name = "InfoColumn`1" FullName = "Om.Common.InfoSet.InfoColumn`1[[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}) Line 83 C#
protobuf-net.dll!ProtoBuf.Meta.MetaType.ApplyDefaultBehaviour() Line 431 + 0x32 bytes C#
Any help in this regard is appreciated. I am planning to rollback my code to previous version of protobuf-net
Below is the class info.
[DataContract]
[ProtoInclude(1, typeof(InfoColumn<Double>))]
[ProtoInclude(2, typeof(InfoColumn<String>))]
[ProtoInclude(3, typeof(InfoColumn<DateTime>))]
[ProtoInclude(4, typeof(InfoColumn<Boolean>))]
public abstract class IInfoColumnBase
{
[DataMember(Order = 101)]
public abstract bool IsSingleValue { get; set; }
[DataMember(Order = 102)]
public abstract string Name { get; set; }
[DataMember(Order = 103)]
public abstract InfoColumnDataType DataType { get; set; }
public abstract long Insert();
public abstract void Insert(long index);
public abstract void SetValue(long index, object val);
public abstract void CopyValues(long start, long end, IInfoColumnBase destCol, long index);
public abstract long GetIndex(object val);
public abstract void Remove(long index);
public abstract object GetValue(long index);
public abstract object GetInternalArrayValue(long index);
public abstract void Clear();
public abstract long Count { get; }
public abstract long ArrayCount { get; }
}
public interface IInfoColumn<T> : IEnumerable<T>
{
T this[double index] { get; set; }
InfoTable Table { get; set; }
double Add(T item);
}
[DataContract(Name = "InfoColumn{0}")]
[KnownType(typeof(InfoColumn<double>))]
[KnownType(typeof(InfoColumn<String>))]
[KnownType(typeof(InfoColumn<bool>))]
[KnownType(typeof(InfoColumn<DateTime>))]
public class InfoColumn<T> : IInfoColumnBase, IInfoColumn<T>
{
long counter = 0;
[DataMember(Order = 1)]
public IList<T> Values { get; set; }
//[DataMember(Order = 2)]
bool isSingleVal = false;
//[DataMember(Order=3)]
public override string Name { get; set; }
//[DataMember(Order=4)]
public override InfoColumnDataType DataType { get; set; }
public InfoTable Table { get; set; }
public override long Count
{
get
{
return this.Table.Count;
}
}
public override long ArrayCount
{
get { return this.Values.Count; }
}
public InfoColumn()
{
}
public InfoColumn(string name,InfoTable table)
{
this.Values = new List<T>();
this.Name = name;
this.Table = table;
}
public override void Clear()
{
this.Values = new List<T>();
}
public override void Remove(long index)
{
int newindex = (int)index;
this.Values.RemoveAt(newindex);
}
public override void CopyValues(long start, long end, IInfoColumnBase destCol, long startIndex)
{
InfoColumn<T> typeCol = destCol as InfoColumn<T>;
for (long ctr = start; ctr <= end; ctr++)
{
typeCol.SetValue(startIndex, this.Values[(int)ctr]);
startIndex++;
}
}
public override void Insert(long rows)
{
if (this.IsSingleValue == true) return;
for (int ctr = 0; ctr < rows; ctr++)
{
this.Values.Add(default(T));
}
}
public T this[double a]
{
get
{
if (a >= this.Count) throw new IndexOutOfRangeException();
long index = (long)a;
if (this.Table.IsFreezed == false)
index = this.Table.CheckData(a);
if (this.isSingleVal == true)
return this.Values[0];
else
return this.Values[(int)index];
}
set
{
if (a >= this.Count) throw new IndexOutOfRangeException();
long index = (long)a;
if (this.Table.IsFreezed == false)
index = this.Table.CheckData(a);
if (this.isSingleVal == true)
this.Values[0] = value;
else
this.Values[(int)index] = value;
}
}
public override long GetIndex(object val)
{
T item = (T)val;
return this.Values.IndexOf(item);
}
public override void SetValue(long index, object val)
{
if (val is InfoSetLink)
this.Values[(int)index] = (T)val;
else
this.Values[(int)index] = (T)Convert.ChangeType(val, typeof(T));
}
public override object GetValue(long index)
{
return this[index];
}
public override object GetInternalArrayValue(long index)
{
return this.Values[(int)index];
}
//[DataMember(Order=5)]
public override bool IsSingleValue
{
get { return isSingleVal; }
set
{
if (isSingleVal == true)
{
this.Values = new List<T>(1);
}
}
}
public override long Insert()
{
if (this.IsSingleValue == true) return -1;
this.Values.Add(default(T));
return this.Values.Count - 1;
}
public double Add(T item)
{
this.Values.Add(item);
return this.Values.Count - 1;
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return new InfoColumnEnumerator<T>(this);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new InfoColumnEnumerator<T>(this);
}
#endregion
}
InfoColumn<T> has a public Add(T) and implements IEnumerable<T> (via IInfoColumn<T>).
There is wider support for list-like types in v2, and it may be that it is trying to interpret the above as a list. Which indeed, it does look a lot like! I will try to take a look to see if this general scenario can be detected and avoided, but it is an edge case (since it is indeed very list-esque).
There is an existing IgnoreListBehaviour switch, however when validating this for the model shown above, it seems that for this specific scenario the "you can't do that" fires before the code that disables list handling; I have changed this in the source, and this will be included in the next release. Basically, you can address this by adding:
[ProtoContract(IgnoreListHandling = true)]
to the impacted type (InfoColumn<T>), with the next build. Which will be shortly, as soon as I've completed validation etc.

Why isn't the Rhino Mock expectation met?

Here is code:
public interface IAccessPoint
{
int BackHaulMaximum { get; set; }
bool BackHaulMaximumReached();
void EmailNetworkProvider();
}
public class AccessPoint : IAccessPoint
{
private IMailProvider Mailer { get; set; }
public AccessPoint(IMailProvider provider)
{
this.Mailer = provider ?? new DefaultMailProvider();
}
public int BackHaulMaximum { get; set; }
public bool BackHaulMaximumReached()
{
if (BackHaulMaximum > 80)
{
EmailNetworkProvider();
return true;
}
return false;
}
public void EmailNetworkProvider()
{
this.Mailer.SendMail();
}
}
public interface IMailProvider
{
void SendMail();
}
public class DefaultMailProvider : IMailProvider
{
public void SendMail()
{
}
}
// Here is the Test, It is not calling EmailNetworkProvider which calls SendMail()
[TestFixture]
public class Tests
{
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateMock<IMailProvider>();
mailerMock.Expect(x => x.SendMail());
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
Assert.IsTrue(accessPoint.BackHaulMaximumReached());
mailerMock.VerifyAllExpectations();
}
}
Any improvement if you use this test?
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateStub<IMailProvider>();
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
var actual = accessPoint.BackHaulMaximumReached();
Assert.AreEqual(true, actual);
mailerMock.AssertWasCalled(x => x.SendMail());
}
As a side-note, BackhaulMaximumReached() is kind of a bizarre design. No notification will be made unless a consumer checks whether the back haul maximum was reached, regardless of the value of BackHaulMaximum.
It is semantically confusing to comingle commands and queries in this way.

Categories