how to use flags attribute with class inherit from enumeration - c#

How to implement multiple selections in a class which inherit from Enumeration With restrictions ?
If I have five schedule types:
Fixed schedule
Rotated schedule
FullTime schedule
PartTime schedule
Flexible schedule
The first two options are versus (Fixed vs Rotated) and the second Two options (FullTime vs PartTime) are versus, I mean the schedule can't be fixed and rotated at the same time or fulltime and parttime at the same time. but It may be Fixed and FullTime for example.
Fixed work schedules which consists of the same number of hours and days worked per week and tend to stay consistent once the number of hours and days have been agreed upon by both the employer and the worker.
Flexible work schedules in which employees and employers work together to determine the number of hours and days of the week they are able to commit to.
Full time work schedule which often require a commitment of 37 - 40 hours per week. Because of the long hours, careers with full time schedules are eligible for work benefits. These benefits can include leave, vacation and sickness, health insurance, and different retirement plan options.
Part time work schedule which is any schedule less than full time employment.
Rotating work schedule which cycle employees through day or week, swing, and night shifts. This cycle helps to distribute different shifts between all employees so that no one is stuck with just the less desirable hours.
So I did the following:
public class Schedule
{
public Schedule()
{
}
private ICollection<ScheduleDetail> _assignedWeeks;
public int Id { get; set; }
public string Name { get; set; }
public int WorkingGroupId { get; set; }
public ScheduleType ScheduleType { get; set; }
public bool IsFixed { get; }
public bool IsFlexible { get; }
public bool IsFullTime { get; }
public ICollection<ScheduleDetail> AssignedWeeks { get => _assignedWeeks; set => _assignedWeeks = value; }
}
public abstract class ScheduleType : Enumeration
{
protected ScheduleType(int value, string displayName) : base(value, displayName)
{
}
public static readonly ScheduleType Fixed
= new FixedType();
public static readonly ScheduleType Flexible
= new FlexibleType();
public static readonly ScheduleType FullTime
= new FullTimeType();
public static readonly ScheduleType PartTime
= new PartTimeType();
public static readonly ScheduleType Rotated
= new RotatedType();
private class FixedType : ScheduleType
{
public FixedType() : base(1, "Fixed Work Schedule")
{
}
}
private class FlexibleType : ScheduleType
{
public FlexibleType() : base(2, "Flexible Work Schedule")
{
}
}
private class FullTimeType : ScheduleType
{
public FullTimeType() : base(3, "Full Time Work Schedule")
{
}
}
private class PartTimeType : ScheduleType
{
public PartTimeType() : base(4, "Part Time Work Schedule")
{
}
}
private class RotatedType : ScheduleType
{
public RotatedType() : base(5, "Rotated Work Schedule")
{
}
}
}
public abstract class Enumeration : IComparable
{
private readonly int _value;
private readonly string _displayName;
protected Enumeration()
{
}
protected Enumeration(int value, string displayName)
{
_value = value;
_displayName = displayName;
}
public int Value
{
get { return _value; }
}
public string DisplayName
{
get { return _displayName; }
}
public override string ToString()
{
return DisplayName;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()
{
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = _value.Equals(otherValue.Value);
return typeMatches && valueMatches;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)
{
var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
return absoluteDifference;
}
public static T FromValue<T>(int value) where T : Enumeration, new()
{
var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
return matchingItem;
}
public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()
{
var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
return matchingItem;
}
private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration, new()
{
var matchingItem = GetAll<T>().FirstOrDefault(predicate);
if (matchingItem == null)
{
var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
throw new ApplicationException(message);
}
return matchingItem;
}
public int CompareTo(object other)
{
return Value.CompareTo(((Enumeration)other).Value);
}
}
So based on the user selection for a specific option or set of options, I have to call a method to set flags (IsFixed,...) in the Schedule class to control the the scheduledetails class in (Fixed and rotated) and the number of hours for(full time and part time)
I'll be grateful for any suggestions or recommendations ?

You're overcomplicating this too much. The first issue I suspect is you (or your business analyst) don't have enough grasp on the busines subject - i.e. shift. What you have here are two, different enumerations:
public enum ScheduleType
{
Unknown = 0,
Fixed,
Rotated
}
public enum ScheduleLoad
{
Unknown = 0,
FullTime,
PartTime
}
Next, in the UI you need two different dropdown boxes / radio groups to allow the user to arrange the shift layout, then save this in two different properties of your object.
However, if you insist on having this in one enumeration, thus one propery with flagged enum values, you need to validate the user input before saving the flags to you store.
[Flags]
public enum ShiftLayout
{
Unknown = 0,
Fixed = 1,
Rotated = 2,
FullTime = 4,
PartTime = 8,
Flexible = 16
}
Then the validation is performed like this:
public bool IsShiftLayoutValid(ShiftLayout layout)
{
var isValid = layout.HasFlag(ShiftLayout.Flexible)
&& (layout & ~ShiftLayout.Flexible) == ShiftLayout.Unknown;
if (!isValid && !layout.HasFlag(ShiftLayout.Flexible))
{
var hasValidSchedule = (layout.HasFlag(ShiftLayout.Fixed) && !layout.HasFlag(ShiftLayout.Rotated))
|| layout.HasFlag(ShiftLayout.Rotated);
var hasValidTime = (layout.HasFlag(ShiftLayout.FullTime) && !layout.HasFlag(ShiftLayout.PartTime))
|| layout.HasFlag(ShiftLayout.PartTime);
isValid = hasValidSchedule && hasValidTime;
}
return isValid;
}

This following ScheduleType example has the ability to hold multiple types similar to how bit fields are used. Note the hex values used for the value of the types that would allow logical operations to determine what types make up the current value.
public class ScheduleType : FlagsValueObject<ScheduleType> {
public static readonly ScheduleType Fixed = new ScheduleType(0x01, "Fixed");
public static readonly ScheduleType Flexible = new ScheduleType(0x02, "Flexible");
public static readonly ScheduleType FullTime = new ScheduleType(0x04, "Full Time");
public static readonly ScheduleType PartTime = new ScheduleType(0x08, "Part Time");
public static readonly ScheduleType Rotated = new ScheduleType(0x10, "Rotated");
protected ScheduleType(int value, string name)
: base(value, name) {
}
private ScheduleType(ScheduleType a, ScheduleType b) {
foreach (var kvp in a.Types.Union(b.Types)) {
Types[kvp.Key] = kvp.Value;
}
Name = string.Join(", ", Types.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Value)) + " Work Schedule";
Value = Types.Keys.Sum();
}
protected override ScheduleType Or(ScheduleType other) {
var result = new ScheduleType(this, other);
//Applying validation rules on new combination
if (result.HasFlag(Fixed) && result.HasFlag(Rotated))
throw new InvalidOperationException("ScheduleType cannot be both Fixed and Rotated");
if (result.HasFlag(FullTime) && result.HasFlag(PartTime))
throw new InvalidOperationException("ScheduleType cannot be both FullTime and PartTime");
return result;
}
}
Using the HasFlag to determine what combination exists within the flag, the desired business rules can be applied.
for example
//Applying validation rules on new combination
if (result.HasFlag(Fixed) && result.HasFlag(Rotated))
throw new InvalidOperationException("ScheduleType cannot be both Fixed and Rotated");
if (result.HasFlag(FullTime) && result.HasFlag(PartTime))
throw new InvalidOperationException("ScheduleType cannot be both FullTime and PartTime");
The rules were applied when combining flags to prevent the creation of any unwanted combinations.
It is derived from the following supporting value objects
FlagsValueObject
public abstract class FlagsValueObject<T> : EnumValueObject where T : FlagsValueObject<T> {
protected readonly IDictionary<int, string> Types = new SortedDictionary<int, string>();
protected FlagsValueObject(int value, string name)
: base(value, name) {
Types[value] = name;
}
protected FlagsValueObject() {
}
public static T operator |(FlagsValueObject<T> left, T right) {
return left.Or(right);
}
protected abstract T Or(T other);
public virtual bool HasFlag(T flag) {
return flag != null && (Value & flag.Value) == flag.Value;
}
public virtual bool HasFlagValue(int value) {
return (Value & value) == value;
}
}
EnumValueObject
public class EnumValueObject : IEquatable<EnumValueObject>, IComparable<EnumValueObject> {
protected EnumValueObject(int value, string name) {
Value = value;
Name = name;
}
protected EnumValueObject() {
}
public virtual string Name { get; protected set; }
public virtual int Value { get; protected set; }
public static bool operator ==(EnumValueObject left, EnumValueObject right) {
return Equals(left, right);
}
public static bool operator !=(EnumValueObject left, EnumValueObject right) {
return !Equals(left, right);
}
public int CompareTo(EnumValueObject other) {
return Value.CompareTo(other.Value);
}
public bool Equals(EnumValueObject other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Value.Equals(other.Value);
}
public override bool Equals(object obj) {
return obj is EnumValueObject && Equals((EnumValueObject)obj);
}
public override int GetHashCode() {
return Value.GetHashCode();
}
public override string ToString() {
return Name;
}
}
Simple example unit test.
[TestClass]
public class ScheduleTypeValueObjectTests {
[TestMethod]
public void Should_Merge_Names() {
//Arrange
var fixedSchedult = ScheduleType.Fixed; //Fixed Work Schedule
var fullTime = ScheduleType.FullTime; // Full Time Work Schedule
var type = fixedSchedult | fullTime;
//Act
var actual = type.Name;
//Assert
actual.Should().Be("Fixed, Full Time Work Schedule");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Should_Fail_Bitwise_Combination() {
//Arrange
var fullTime = ScheduleType.FullTime; // Full Time Work Schedule
var partTime = ScheduleType.PartTime;
var value = fullTime | partTime;
}
}
The HasFlag property allows the ability to check what types exist within the flag as demonstrated in the following example.
public class Schedule {
public Schedule(
//...
ScheduleType scheduleType
//...
) {
//...
ScheduleType = scheduleType;
}
//...
public ScheduleType ScheduleType { get; set; }
public bool IsFixed {
get {
return ScheduleType != null && ScheduleType.HasFlag(ScheduleType.Fixed);
}
}
public bool IsFlexible {
get {
return
ScheduleType != null && ScheduleType.HasFlag(ScheduleType.Flexible);
}
}
public bool IsFullTime {
get {
return
ScheduleType != null && ScheduleType.HasFlag(ScheduleType.FullTime);
}
}
//...
}

Just use 2 enums.
1 for Work type (fixed etc)
and 1 for work load (full time etc)
then a bool for flexible.
Do not complicate things for no reason, as, looking at what you did, you put up a lot of unnecessary code to do a comparison.
If you really want to keep everything in one enum, you will save so much more code by doing an enum like
Fixed
FixedFullTime
FixedPartTime
Rotated
RotatedFullTime
RotatedPartTime
etc etc etc with all the combinations.
You have a low number of enum combinations and it's not worth doing custom code to check all the combinations with an IComparable
Just use different enums and in your schedule class those
public bool IsFixed { get; }
public bool IsFlexible { get; }
public bool IsFullTime { get; }
with a comparison between Fixed/Rotated, Fulltime/Parttime etc etc
or use only a single enum.

As I said in my first answer - this is too complicated. But achievable.
When I re-read the post title I realized that you might want to apply the logical operations to the class, used instead of a standard C# enum. For that matter, one needs to implement the operators themselves. So I played a bit to get my hands dirty and voila...
First, define the dummy Enumeration class.
public abstract class Enumeration
{
public virtual int Id { get; set; }
public virtual string Description { get; protected set; }
}
Note that I've dropped most of the methods from your implementation. Some (Equals, GetAll) are removed for brevity, but others (FromValue<T>) have improved implementation later; keep reading ...
public partial class ShiftVariant : Enumeration
{
#region Variations' classes
private class FixedShiftVariation : ShiftVariant
{
public FixedShiftVariation()
{
Id = FixedShiftId;
Description = "Fixed Shift";
}
}
private class RotatedShiftVariant : ShiftVariant
{
public RotatedShiftVariant()
{
Id = RotatedShiftId;
Description = "Rotated Shift";
}
}
private class FullTimeShiftVariation : ShiftVariant
{
public FullTimeShiftVariation()
{
Id = FullTimeShiftId;
Description = "Full-time Shift";
}
}
private class PartTimeShiftVariation : ShiftVariant
{
public PartTimeShiftVariation()
{
Id = PartTimeShiftId;
Description = "Part-time Shift";
}
}
private class FlexibleShiftVariation : ShiftVariant
{
public FlexibleShiftVariation()
{
Id = FlexibleShiftId;
Description = "Flexible Shift";
}
}
#endregion
protected static int FixedShiftId = 2;
protected static int RotatedShiftId = 4;
protected static int FullTimeShiftId = 8;
protected static int PartTimeShiftId = 16;
protected static int FlexibleShiftId = 32;
public static ShiftVariant NotSet = new ShiftVariant() { Id = 0, Description = "Unknown" };
public static ShiftVariant FixedShift = new FixedShiftVariation();
public static ShiftVariant RotatedShift = new RotatedShiftVariant();
public static ShiftVariant FullTimeShift = new FullTimeShiftVariation();
public static ShiftVariant PartTimeShift = new PartTimeShiftVariation();
public static ShiftVariant FlexibleShift = new FlexibleShiftVariation();
private static Dictionary<int, ShiftVariant> AllTheVariations = new Dictionary<int, ShiftVariant>
{
{ FixedShiftId, FixedShift },
{ RotatedShiftId, RotatedShift },
{ FullTimeShiftId, FullTimeShift },
{ PartTimeShiftId, PartTimeShift },
{ FlexibleShiftId, FlexibleShift }
};
/// <summary>
/// Enable initialization off of an integer.
/// This replaces your FromValue<T> method. You can repeat it for strings too, matching the descriptions.
/// </summary>
/// <param name="id"></param>
public static implicit operator ShiftVariant(int id)
{
return AllTheVariations.ContainsKey(id) ? AllTheVariations[id] : new ShiftVariant { Id = id };
}
/// <summary>
/// Enable binary OR
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static ShiftVariant operator |(ShiftVariant left, ShiftVariant right)
{
return new ShiftVariant
{
Id = left.Id | right.Id,
};
}
/// <summary>
/// Enable binary AND
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static ShiftVariant operator &(ShiftVariant left, ShiftVariant right)
{
return new ShiftVariant
{
Id = left.Id & right.Id
};
}
/// <summary>
/// Enable COMPLEMENT ONE'S (negation)
/// </summary>
/// <param name="left"></param>
/// <returns></returns>
public static ShiftVariant operator ~(ShiftVariant left)
{
return new ShiftVariant
{
Id = ~left.Id
};
}
private string CalculatedDesc = null;
public override string Description
{
get => CalculatedDesc ?? CalculateDescription();
protected set => CalculatedDesc = value;
}
public override string ToString()
{
return Description;
}
/// <summary>
/// Figure out the description by walking currently set flags
/// </summary>
/// <returns></returns>
private string CalculateDescription()
{
CalculatedDesc = string.Empty;
if (AllTheVariations.ContainsKey(Id))
{
CalculatedDesc = AllTheVariations[Id].Description;
}
else
{
foreach (var variation in AllTheVariations)
{
if ((Id & variation.Key) == variation.Key)
{
CalculatedDesc += " | " + variation.Value.Description;
}
}
CalculatedDesc = CalculatedDesc.TrimStart(" |".ToCharArray());
}
return CalculatedDesc;
}
}
The main class - ShiftVariant - is declared private so at a later point (perhaps in another assembly) you can extend it with new enumerations like so:
public class ShiftVariant
{
private class SomeOtherShiftVariation : ShiftVariation
{
// ...
}
protected static int SomeOtherShiftId = 64;
public static ShiftVariation SomeShift = new SomeOtherShiftVariation();
// add the new shift variation to AllTheVariations dictonary
}

I would use 1 enumerator type and annotate them as flags, you this by placings [Flags] on top of the enumerator.
You can then make read-only properties or declare them in the enum. that contain groups of any of the flags making those flags valid for that choice. This way you would not only have valid options but you can re-use this in a database by checking if a flag is in bit-wise group. just as you could in your code.
Here is what I think is a simple one that all can relate to:
[Flags]
public enum Role
{
None=0
NormalUser = 1,
Moderator = 2,
Accounting = 4,
Membership = 8,
Blocked = 16
BackOffice = Membership | Accounting | Moderator
Admin = NormalUser | Moderator | Membership
}
You can store all in a property of Type Role.
You can be a BackOffice role and be blocked, you test this in c#
using a bitwise compare
if(testRole & Role.Blocked == Role.Blocked)
{
return;//blocked user
}
Here is a nice article about bitwise testing in TSQL, bitwise operations are fast and available in all databases i think

Flags Attribute is generally used when you have lists of elements with combinations. You use it with Bitwise operations only. You can find the full details here.
https://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.110).aspx

Related

Overriding IEquatable<T> when T is an interface and hashcodes are different between derived types

I have A and B classes both implementing interface I.
public interface I
{
int SomeInt { get; }
bool SomeBool { get; }
float SomeFloat { get; }
}
public class A : I
{
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private readonly string _someARelatedStuff;
// Rest of class...
}
public class B : I
{
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private string readonly _someBRelatedStuff;
private double readonly _someOtherBRelatedStuff;
// Rest of class...
}
Sometimes I want to test equality between A and B (usually when comparing lists of A and lists of B) based on the equality of their I properties (SomeInt, SomeBool, SomeFloat), so I implemented IEquatable<I> on both and I compare them based on their shared I properties values.
The problem is that I already have an implementation for GetHashCode() on both A and B that produces different hashes because I'm taking into account additional members.
B does not depend on A so I use interface I to compare them and it has a list of properties with getters.
I read in a StackOverflow answer that:
If you are implementing a class, you should always make sure that two equal objects have the same hashcode.
So does that mean that everytime a class A want to be implement interface I, and I want to be able to compare instances that implement I, I have to make sure the hashcode is calculated in the same way for all instances of I and only use I properties?
I do feel like I'm not intended to implement IEquatable<T> when T is an interface, but my alternatives are:
Using regular inheritance with a base class - I rather avoid inheritance when possible, and this solution won't work if B needs to derive from some framework C class because of single inheritance
Implement equality checks between A and B with a method on either A or B - will create code duplication
Have an equality check method between I instances defined in I - sounds like the best option
Are there any options that I'm missing?
Consider making the a IEqualityComparer<> class to compare the common values.
I have renamed the interface to ICommon for readability
public interface ICommon
{
int SomeInt { get; }
bool SomeBool { get; }
float SomeFloat { get; }
}
public class CommonComparer : IEqualityComparer<ICommon>
{
public bool Equals(ICommon x, ICommon y)
{
return x.SomeInt.Equals(y.SomeInt)
&& x.SomeBool.Equals(y.SomeBool)
&& x.SomeFloat.Equals(y.SomeFloat);
}
public int GetHashCode(ICommon obj)
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295)*hc + obj.SomeInt.GetHashCode();
hc = (-1521134295)*hc + obj.SomeBool.GetHashCode();
hc = (-1521134295)*hc + obj.SomeFloat.GetHashCode();
return hc;
}
}
}
and the program can distinguish between the equal items on two lists.
class Program
{
static void Main(string[] args)
{
var listA = new List<A>
{
new A(1001, true, 1.001f, "A1"),
new A(1002, true, 1.002f, "A2"),
new A(1003, false, 1.003f, "A1"),
new A(1004, false, 1.004f, "A4")
};
var listB = new List<B>
{
new B(1001, true, 1.001f, "B1", 2.5),
new B(1002, false, 1.002f, "B2", 2.8),
new B(1003, true, 1.003f, "B3", 2.9),
new B(1004, false, 1.004f, "B4", 2.9)
};
var common = Enumerable.Intersect(listA, listB, new CommonComparer()).OfType<ICommon>();
Console.WriteLine($"{"SomeInt",-8} {"Bool",-6} {"SomeFloat",-10}");
foreach (var item in common)
{
Console.WriteLine($"{item.SomeInt,-8} {item.SomeBool,-6} {item.SomeFloat,-10}");
}
//SomeInt Bool SomeFloat
//1001 True 1.001
//1004 False 1.004
}
}
and the rest of the code definitions
public class A : ICommon, IEquatable<A>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private readonly string _someARelatedStuff;
// Rest of class...
public A(ICommon other, string someARelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someARelatedStuff)
{ }
public A(int someInt, bool someBool, float someFloat, string someARelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someARelatedStuff = someARelatedStuff;
}
public override string ToString() => _someARelatedStuff;
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is A other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(A other)
{
return comparer.Equals(this, other)
&& _someARelatedStuff.Equals(other._someARelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someARelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}
public class B : ICommon, IEquatable<B>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
readonly string _someBRelatedStuff;
readonly double _someOtherBRelatedStuff;
// Rest of class...
public B(ICommon other, string someBRelatedStuff, double someOtherBRelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someBRelatedStuff, someOtherBRelatedStuff)
{ }
public B(int someInt, bool someBool, float someFloat, string someBRelatedStuff, double someOtherBRelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someBRelatedStuff = someBRelatedStuff;
this._someOtherBRelatedStuff = someOtherBRelatedStuff;
}
public override string ToString() => $"{_someBRelatedStuff}, {_someOtherBRelatedStuff.ToString("g4")}";
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is B other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(B other)
{
return comparer.Equals(this, other)
&& _someBRelatedStuff.Equals(other._someBRelatedStuff)
&& _someOtherBRelatedStuff.Equals(other._someOtherBRelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someBRelatedStuff.GetHashCode();
hc = (-1521134295)*hc + _someOtherBRelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}

Using Enumeration Class

I'm new to C# and I'm relatively new to abstract classes and inheritance and I'm having troubles understanding how to use them. I have this abstract enumeration class:
public abstract class Enumeration : IComparable
{
public uint Id { get; private set; }
public string Name { get; private set; }
public uint MaxTemperature { get; private set; }
public double Density { get; private set; }
protected Enumeration()
{
}
protected Enumeration(uint id, string name, uint maxTemprature, double density)
{
Id = id;
Name = name;
MaxTemperature = maxTemprature;
Density = density;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration,
new()
{
var type = typeof(T);
var fields = type.GetTypeInfo().GetFields(BindingFlags.Public
| BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = Id.Equals(otherValue.Id);
return typeMatches && valueMatches;
}
public int CompareTo(object other)
{
return Id.CompareTo(((Enumeration)other).Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
This class is inherited by my material class:
class Material : Enumeration
{
public static readonly Material FreeSpace =
new Material(0, "Free Space", 0, 0);
public static readonly Material CarbonSteel =
new Material(1, "Carbon Steel", 2500, 0.284);
private Material()
{
}
private Material(uint id, string name, uint maxTemperature,
double density) : base(id, name, maxTemperature, density)
{
}
private static IEnumerable<Material> List()
{
return new[] { FreeSpace, CarbonSteel };
}
}
Now I want to use these materials in my part class:
class Part
{
private Material partMaterial;
public Part() { }
public Material PartMaterial
{
set
{
partMaterial = value;
}
}
}
This is where I'm stuck, how do I set a variable as one of the enumerated static objects so I can get the properties from those?
You can use SelectedItem instead of SelectedIndex
part.PartMaterial = (Material) MaterialCombo.SelectedItem;
So, I wish I would have left the question the way it was, because in the end it was the correct way to ask the question. But after the snide comments and down grading I changed it to what I thought was better. The way the original question should have been answered was:
Since you are enumerating the materials class, you need a method to expose the Enumerated values of the objects. The
IEnumerable<Material> List() method should be made public to accomplish this.
You can then use MaterialCombo.DataSource = Material.List() to populate the combobox with the material objects and MaterialCombo.DisplayMember = "Name"; to display the names of those objects in the combobox.
Finally, use #Oxald's answer to pass the material to your part class.
Thank you #Mark Benningfield for pointing me in the direction to search for "Using an enum to populate a combobox" which was helpful.
And Oxald for suggesting to use .SelectedItem instead of .SelectedIndex.

Mocking adding items to a list in .NET NMock2

I'm using NMock2 (2.1.3641.27570) in my unit tests.
IList<MyObj> values = _mock.NewMock<IList<MyObj>>();
That mock I return when my tested object calls the Values get property on my mocked object:
Expect.AtLeastOnce.On(_myKeepMock).GetProperty("Values").Will(Return.Value(values));
Then I expect value which is a MyObj to be added to my list values:
Expect.AtLeastOnce.On(values).Method("Add").With(value);
In order to avoid unexpected invocation of list'1.Add upon execution I understand I have to override the Equals method in the MyObj class:
public override bool Equals(object obj) { ...}
and compare by value instead of reference. But it doesn't even get called when executing the test (breakpoint not hit).
What do I need to do in order to pass the test when the item added to the list in the call is equal in value to the one added by the tested object?
I read about custom matchers but not sure if those apply here.
UPDATE
Full example:
using System.Collections.Generic;
using System.Linq;
using NMock2;
using NUnit.Framework;
public class Data
{
public int Val { get; set; }
public Data(int val) { Val = val; }
}
public class ModData
{
public int Val { get; set; }
protected bool Equals(ModData other)
{
return this.Val.Equals(other.Val);
}
public override int GetHashCode()
{
return this.Val.GetHashCode();
}
public override bool Equals(object obj)
{
ModData m = (ModData)obj;
return m != null && this.Val == m.Val;
}
}
public interface IAllData
{
IList<Data> Data { get; set; }
IList<ModData> ModData { get; set; }
}
public class AllData : IAllData
{
public IList<Data> Data { get; set; }
public IList<ModData> ModData { get; set; }
}
public class Calco
{
private IAllData _allData;
public Calco(IAllData allData)
{
_allData = allData;
}
public void Sum()
{
_allData.ModData.Add(new ModData { Val = _allData.Data.Sum(d => d.Val) });
}
}
public class CalcoTest
{
[Test]
public void Test()
{
Mockery mockery = new Mockery();
IList<Data> data = new List<Data>();
IList<ModData> modData = mockery.NewMock<IList<ModData>>();
IAllData allData = mockery.NewMock<IAllData>();
ModData modDatum = new ModData { Val = 4 };
data.Add(new Data(1));
data.Add(new Data(10));
Calco c = new Calco(allData);
Expect.AtLeastOnce.On(allData).GetProperty("Data").Will(Return.Value(data));
Expect.AtLeastOnce.On(allData).GetProperty("ModData").Will(Return.Value(modData));
Expect.AtLeastOnce.On(modData).Method("Add").With(modDatum);
c.Sum();
mockery.VerifyAllExpectationsHaveBeenMet();
}
}
Output:
NMock2.Internal.ExpectationException : unexpected invocation of list`1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
Expected:
at least 1 time: allData.Data, will return <System.Collections.Generic.List`1[WRM.Common.RiskCalculation.Tests.Data]> [called 1 time]
at least 1 time: allData.ModData, will return <list`1> [called 1 time]
at least 1 time: list`1.Add(equal to <WRM.Common.RiskCalculation.Tests.ModData>) [called 0 times]
Notice how it expects invocation of list'1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
and then shows it didn't call list'1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
Custom Matchers ARE the answer: http://nmock.sourceforge.net/advanced.html
public class IsMod
{
public static Matcher Equal(ModData otherMod)
{
return new ModMatcher(otherMod);
}
}
internal class ModMatcher : Matcher
{
private readonly ModData _mod;
public ModMatcher(ModData mod)
{
_mod = mod;
}
public override bool Matches(object o)
{
ModData m = (ModData)o;
return _mod.Val.Equals(m.Val);
}
public override void DescribeTo(TextWriter writer)
{
writer.Write("Value same ");
writer.Write(_mod.Val);
}
}
And then
Expect.AtLeastOnce.On(modData).Method("Add").With(IsMod.Equal(modDatum));
Done!

How to generate a unique hash for a collection of objects independent of their order [duplicate]

This question already has answers here:
Getting hash of a list of strings regardless of order
(5 answers)
Closed 8 years ago.
Let's say I have a class
public class MyClass
{
public string Type { get; set; }
public int Id { get; set; }
}
and I have a collection class that is simply a strongly typed List
public class MyClassList : List<MyClass>
{
public MyClassList(IEnumerable<MyClass> enumerable) : base (enumerable) {}
}
I want MyClassList to be able to generate a unique hash-code for MyClassList based on the contents. The hash-code of MyClass should be based on both properties. The hash-code of MyClassList should be the same even if the order of the objects is different.
To handle the ordering issue I was thinking I could order the list before generating the hash-code, but I'm not sure how to generate the hash-code of the list.
For optimal performance I would try to avoid iterating the whole collection every time GetHashCode is called. The purpose of GetHashCode is to improve performance to a point better than evaluating every element. So I might try maintaining the hash code when elements in the list are changed like this.
class Program
{
static void Main(string[] args)
{
MyClassList l = new MyClassList() { new MyClass() {Type="Bob", Id=1}, new MyClass() {Type="Jones", Id=2}};
MyClassList l2 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }, new MyClass() { Type = "Bob", Id = 1 } };
MyClassList l3 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }};
Console.WriteLine("{0} {1} {2}", l.GetHashCode(), l2.GetHashCode(), l3.GetHashCode());
l3.Add(new MyClass() { Type = "Bob", Id = 1 });
Console.WriteLine("{0}", l3.GetHashCode());
}
}
public class MyClass
{
public string Type { get; set; }
public int Id { get; set; }
public override int GetHashCode()
{
return (Type.GetHashCode() % 0x8000) | (int)((uint)Id.GetHashCode() & 0xFFFF0000);
}
}
public class MyClassList : IList<MyClass>
{
List<MyClass> internalList;
int hashCode = 0;
public MyClassList()
{
internalList = new List<MyClass>();
}
private void IncludeInHash(MyClass item)
{
hashCode ^= item.GetHashCode();
}
private void ExcludeFromHash(MyClass item)
{
IncludeInHash(item);
}
public override int GetHashCode()
{
return hashCode;
}
public int IndexOf(MyClass item)
{
return internalList.IndexOf(item);
}
public void Insert(int index, MyClass item)
{
internalList.Insert(index, item);
// Make sure Insert is successful (doesn't throw an exception) before affecting the hash
IncludeInHash(item);
}
public void RemoveAt(int index)
{
MyClass reduce = internalList[index];
internalList.RemoveAt(index);
// Make sure RemoveAt is successful before affecting the hash
ExcludeFromHash(reduce);
}
public MyClass this[int index]
{
get
{
return internalList[index];
}
set
{
MyClass reduce = internalList[index];
internalList[index] = value;
// Make sure these happen atomically; don't allow exceptions to prevent these from being accurate.
ExcludeFromHash(reduce);
IncludeInHash(value);
}
}
public void Add(MyClass item)
{
internalList.Add(item);
IncludeInHash(item);
}
public void Clear()
{
internalList.Clear();
hashCode = 0;
}
public bool Contains(MyClass item)
{
return internalList.Contains(item);
}
public void CopyTo(MyClass[] array, int arrayIndex)
{
internalList.CopyTo(array, arrayIndex);
}
public int Count
{
get { return internalList.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(MyClass item)
{
if (internalList.Remove(item))
{
ExcludeFromHash(item);
return true;
}
else
return false;
}
public IEnumerator<MyClass> GetEnumerator()
{
return internalList.AsReadOnly().GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The solution given by clto works. Here is an alternative: sort the list by some total ordering (any ordering will do, as long as it is unambiguous). Then you can calculate the hash code using any normal means. You don't need order-independence. You could even use a cryptographic hash function.
I propose this solution (I didn't implement the Equals method) :
public class MyClass
{
public string Type { get; set; }
public int Id { get; set; }
public override int GetHashCode()
{
int hash = 17;
hash = hash + 23 * this.Type.GetHashCode();
hash = hash + 23 * this.Id.GetHashCode();
return hash;
}
}
public class MyClassList : List<MyClass>
{
public MyClassList(IEnumerable<MyClass> enumerable) : base(enumerable) { }
public override int GetHashCode()
{
return this.Aggregate(17, (state, current) => state * 23 + current.GetHashCode());
}
}
The way to generate the hashcode is inspired from Microsoft method to compute the hash value for anonymous objects.
If the order isn't important then you should use a collection that inherently is a set, rather than a list.
Also, it's generally best to not inherit from collections; use composition instead.
So for a collection you can use a HashSet, as it will have set semantics.
To have MyClass use both properties as it's identity just override it's equals and get hash code implementations, or create an IComparer<MyClass> if you can't or don't want to do that.
public class MyClass:IEquatable<MyClass>
{
public string Type { get; set; }
public int Id { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as MyClass);
}
public bool Equals(MyClass other)
{
if (other == null)
return false;
return Type == other.Type &&
Id == other.Id;
}
public override int GetHashCode()
{
return Type.GetHashCode() * 79 + Id;
}
}
Then your collection is as simple as:
HashSet<MyClass> set = new HashSet<MyClass>();
And if you want to compare various sets just use:
HashSet<MyClass>.CreateSetComparer();

How do I implement equality for an abstract base class?

I'm following the MSDN guidance for value equality, and I found a case that the documentation didn't cover, equality for a base class.
A little background:
I'm working on a Mahjong game (4-player, not matching), and I'm working on defining the tiles. Tiles can be broken into two groups: suits, which have a number associated with them (and can be put together in sequences, like 2-3-4) and honor tiles, which have no number.
Here's what I have so far:
public enum MahjongSuitType
{
Bamboo = 1,
Character,
Dot
}
public enum MahjongSuitNumber
{
One = 1,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine
}
public enum MahjongHonorType
{
GreenDragon = 1,
RedDragon,
WhiteDragon,
EastWind,
SouthWind,
WestWind,
NorthWind
}
public abstract class MahjongTile
{
}
public class MahjongSuitTile : MahjongTile, IEquatable<MahjongTile>
{
public MahjongSuitType SuitType { get; private set; }
public MahjongSuitNumber SuitNumber { get; private set; }
public bool IsRedBonus { get; private set; } //this has no bearing on equality
public MahjongSuitTile(MahjongSuitType suitType,
MahjongSuitNumber suitNumber,
bool isRedBonus = false)
{
this.SuitType = suitType;
this.SuitNumber = suitNumber;
this.IsRedBonus = isRedBonus;
}
public override bool Equals(object obj)
{
return this.Equals(obj as MahjongTile);
}
public bool Equals(MahjongTile other)
{
if (Object.ReferenceEquals(other, null))
return false;
if (Object.ReferenceEquals(other, this))
return true;
MahjongSuitTile otherSuitTile = other as MahjongSuitTile;
if (Object.ReferenceEquals(otherSuitTile, null))
return false;
return (this.SuitType == otherSuitTile.SuitType) &&
(this.SuitNumber == otherSuitTile.SuitNumber);
}
public override int GetHashCode()
{
return this.SuitType.GetHashCode() ^ this.SuitNumber.GetHashCode();
}
}
public class MahjongHonorTile : MahjongTile, IEquatable<MahjongTile>
{
public MahjongHonorType HonorType { get; private set; }
public MahjongHonorTile(MahjongHonorType honorType)
{
this.HonorType = HonorType;
}
public override bool Equals(object obj)
{
return this.Equals(obj as MahjongTile);
}
public bool Equals(MahjongTile other)
{
if (Object.ReferenceEquals(other, null))
return false;
if (Object.ReferenceEquals(other, this))
return true;
MahjongHonorTile otherHonorTile = other as MahjongHonorTile;
if (Object.ReferenceEquals(otherHonorTile, null))
return false;
return this.HonorType == otherHonorTile.HonorType;
}
public override int GetHashCode()
{
return this.HonorType.GetHashCode();
}
}
For the majority of the code, I'd like to refer to the tiles via the base class, something like:
List<MahjongTile> hand = new List<MahjongTile>() { ... };
HashSet<MahjongTile> dragonTiles = new HashSet()
{
new MahjongHonorTile(MahjongHonorType.GreenDragon),
new MahjongHonorTile(MahjongHonorType.RedDragon),
new MahjongHonorTile(MahjongHonorType.WhiteDragon)
}
IEnumerable<MahjongTile> dragonTilesInHand = hand.Where(t => dragonTiles.Contains(t));
My Question: how should I define equality in the MahjongTile base class?
Since Object.Equals is virtual, the subclasses implementation override the method. No further code is needed.

Categories

Resources