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
So I have got these 2 instance types "FirstType" and "SecondType" which inherit from the mother class "ContaBancaria". They both return text from different textboxes. Basically, they do the same thing, but I need 2 instances for 2 different list types (I probably don't think the list has anything to do with my question, so I'll proceed not to go in detail)
Here are the instances:
private FirstType AddTypeFirst()
{
return new FirstType(textBoxNumber.Text,
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
private SecondType AddTypeSecond()
{
return new SecondType(textBoxNumber.Text,
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
Is there a way to return these 2 instances with the same method type?
EDIT:
What I meant was to return these 2 different types of instances with 1 single method, for example:
private [type?] AddInstance()
{
return new [type*] textBoxNumber.Text, //* the type could be FirstType or SecondType
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
EDIT 2:
ContaBancaria looks like this:
abstract class ContaBancaria
{
public string number { get; set; }
public string balance { get; set; }
public Client data { get; set; }
}
And, since there's Client...
class Client
{
public string name;
public string address;
public string birth;
}
Hope you get me.
You can use generic method and derrived classes I think.
For example, you have two classes and you want to receive one of them. Those classes are named "FirstSon" and "SecondSon" and both of them are derrived from class "Father".
class Father
{
string myName;
public string MyName
{
get { return myName; }
set { myName = value; }
}
public Father()
{
myName = "John";
}
}
class FirstSon : Father
{
string mySecondName;
public string MySecondName
{
get { return mySecondName; }
set { mySecondName = value; }
}
public FirstSon()
{
mySecondName = "Bill";
}
}
class SecondSon : Father
{
int age;
public int Age
{
get { return age; }
set { age = value; }
}
string mySecondName;
public string MySecondName
{
get { return mySecondName; }
set { mySecondName = value; }
}
public SecondSon()
{
mySecondName = "Drake";
age = 21;
}
}
And you have method GetObject(). This method is generic. It receives type of class, then checks what type it has received and returnes the new object with the same type.
public static T GetObject<T>() where T: Father
{
var firstSon = new FirstSon();
var secondSon = new SecondSon();
if (firstSon.GetType() == typeof(T))
return (T)Convert.ChangeType(firstSon, typeof(T));
return (T)Convert.ChangeType(secondSon, typeof(T));
}
It uses method Convert.ChangeType(object value, Type conversonType) and allows you to convert your object to your type.
But I am not convinced that this is a good idea according to How do I make the return type of a method generic?
Assuming you want to return the proper type based on the list being added to, you will need to write your own generic Add function, and use Reflection to figure out the type:
public static class Ext {
public static void AddInstancia<T>(this List<T> aList) where T : class {
if (typeof(T) == typeof(FirstType))
aList.Add(AddTypeFirst() as T);
else
aList.Add(AddTypeSecond() as T);
}
}
I see no good reason to do this - after all, you know the type of the list, just call the correct function for that list...
Instead of using Reflection, you could also use dynamic if you add some functions to each sub-type:
public class FirstType : Parent {
public FirstType MakeChild() {
return new FirstType();
}
}
public class SecondType : Parent {
public SecondType MakeChild() {
return new SecondType();
}
}
public static class Static<T> where T : new() {
public static dynamic Value = new T();
}
public static class Ext {
public static void AddInstance<T>(this List<T> aList) where T : new() {
aList.Add(Static<T>.Value.MakeChild());
}
}
Which you can call like
var list1 = new List<FirstType>();
list1.AddInstance();
Hi I have created few nested iEnumerable implemented classes.
CDSWorkflowCollection
CDSModuleCollection
CDSSystemCollection
Below are my Classes
public class cdssystems
{
public string cdsSystemName;
public CDSModuleCollection listModules;
}
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
class cdsdelgate
{
private string delgateName;
private DateTime fromDate;
private DateTime toDate;
private string functionElement;
private CDSSystemCollection cdsSystemsList;
private string cdsComments;
private string JobTitle;
}
public class cdsworkflows
{
public string WorkflowName;
public string ActionGroup;
}
class CDSWorkflowCollection : ICollection, IEnumerable<cdsworkflows>
{
private List<cdsworkflows> cdsWorkflowList;
private readonly object syncObject = new object();
public CDSWorkflowCollection(IEnumerable<cdsworkflows> cdsWorkflowList)
: base()
{
this.cdsWorkflowList = new List<cdsworkflows>(cdsWorkflowList);
}
public IEnumerator<cdsworkflows> GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
if ((array.Rank != 1) || ((this.Count + index) > array.Length))
{
throw new ArgumentException();
}
int count = 0;
foreach (cdsworkflows cssWorkflow in this.cdsWorkflowList)
{
array.SetValue(cssWorkflow, count++);
}
}
public int Count
{
get
{
return this.cdsWorkflowList.Count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this.syncObject;
}
}
}
class CDSSystemCollection : ICollection, IEnumerable<cdssystems>
{
private List<cdssystems> cdsSystemList;
private readonly object syncObject = new object();
public CDSSystemCollection(IEnumerable<cdssystems> cdsSystemList)
: base()
{
this.cdsSystemList = new List<cdssystems>(cdsSystemList);
}
//Rest of the code here
}
class CDSDelegateCollection : ICollection, IEnumerable<cdsdelgate>
{
private List<cdsdelgate> cdsDelegateist;
private readonly object syncObject = new object();
public CDSDelegateCollection(IEnumerable<cdsdelgate> cdsDelegateList)
: base()
{
this.cdsDelegateist = new List<cdsdelgate>(cdsDelegateList);
}
//Rest of the code here
}
No i want to add objects to the class using group by and my code goes like below
var results = (from SPListItem item in myItemsList
group item by item["Systems"]
into grp
select new cdssystems()
{
cdsSystemName = grp.Key.ToString(),
listModules = (from item in grp
group item by item["Modules"]
into grpModules
select new cdsmodules()
{
moduleName = grpModules.Key.ToString(),
listWorkflows = (from item in grpModules
group item by item["Workflows"]
into grpWorkflows
select new cdsworkflows()
{
WorkflowName = grpWorkflows.Key.ToString(),
ActionGroup = grpWorkflows.FirstOrDefault()["ActionGroup"].ToString()
}
).ToList()
}).ToList()
}).ToList();
I am getting Error in ToList() saying
Cannot implicitly convert type 'System.Collections.Generic.List' to 'CDS.BusinessObjects.CDSWorkflowCollection'
I know the parm expects a collection and i am passing List. How to pass the collection. Please help
Delete your custom collection types and use the Generic ones from the .net framework instead. You can use List<T>, IList<T>, or ICollection<T>. There is almost never a need to write your own collection implementation(s).
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
becomes
public class cdsmodules
{
public string moduleName { get; set; }
public List<cdsworkflows> listWorkflows { get; set; }
}
You should also follow proper visibility guidelines by never exposing fields directly. Instead use a property with a get;set; accessor. Fields should almost always be scoped as private or protected.
I want to create a class with a property that "variably" points to some other property in another class.
Imagine a class (called "Limiter") with several integer properties (Limit1, Limit2, etc).
I now want a second class ("LimitWatcher") which can "watch" one of those limits. But I want to be able to set which particular limit it is watching in the constructor. I eventually want several instances of LimitWatcher, each one pointing to a separate Limit. The Limit values themselves may change after the Watchers have been instantiated, but the watcher must always see the current value of the Limit that it is watching. So basically, I want to store a reference to an integer.
I know I can accomplish this using reflection (see example below), but I feel as though there might be a simpler way.
using System;
namespace ConsoleApplication4
{
public class Limiter
{
public int limit1 { get; set; } = 10;
public int limit2 { get; set; } = 20;
public void Update()
{
limit1++;
limit2++;
}
}
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
}
private Limiter myLimiter { get; }
public string limitName { get; set; }
//can I do this without reflection:
public int FooLimit { get { return (int)typeof(Limiter).GetProperty(limitName).GetValue(myLimiter); } }
}
class Program
{
static void Main(string[] args)
{
Limiter lim = new ConsoleApplication4.Limiter();
LimitWatcher w1 = new LimitWatcher(lim, nameof(lim.limit1));
LimitWatcher w2 = new LimitWatcher(lim, nameof(lim.limit2));
lim.Update();
Console.WriteLine($"1st watcher sees {w1.FooLimit}"); //11
Console.WriteLine($"2nd watcher sees {w2.FooLimit}"); //21
Console.ReadKey();
}
}
}
You could use a Func int the constructor, something like:
private Limiter limiter;
private Func<Limiter, int> propertyAccesor;
public LimitWatcher(Limiter lim, string propName, Func<Limiter, int> propertyAccesor)
{
this.propertyAccesor = propertyAccesor;
}
public bool LimitExceeded()
{
int propertyValue = propertyAccesor(limiter);
return propertyValue > 20;
}
You could use dynamic expressions:
using System.Linq.Expressions;
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
var parameter = Expression.Parameter(typeof(Limiter), "x");
var member = Expression.Property(parameter, propName);
var finalExpression = Expression.Lambda<Func<Limiter, int>>(member, parameter);
getter = finalExpression.Compile();
}
private Func<Limiter, int> getter;
private Limiter myLimiter { get; }
public string limitName { get; set; }
public int FooLimit { get { return getter(myLimiter); } }
}
Inspired by this article
I have a multilingual database, which returns values based on a key and an enum Language. When I convert a DB object to a model, I want the model to contain the translated value based on the key and the current language.
The key comes from the DB object but how can I pass the current language to the the Mapper.Map() function?
Currently, I am using a [ThreadStatic] attribute to set the culture before calling Mapper.Map<>, and to retrieve it in the TypeConverter.
public enum Language
{
English, French, Italian, Maltese
}
public class MultilingualValue<T>
{
public Dictionary<Language, T> Value { get; set; }
public MultilingualValue()
{
this.Value = new Dictionary<Language, T>();
}
}
public class PersonData
{
public string FirstName { get; set; }
public MultilingualValue<string> City { get; set; }
}
public void MapPerson()
{
PersonData personData = new PersonData();
personData.FirstName = "John";
personData.City = new MultilingualValue<string>();
personData.City.Value[ Language.English] = "The Zurrieq";
personData.City.Value[Language.French] = "Le Zurrieque";
MultilingualValueData.CurrentLanguage = Language.English;
var personModel = Mapper.Map<PersonData, PersonModel>(personData);
}
public class MultilingualValueToBasicDataTypeConverter<T> : ITypeConverter<MultilingualValue<T>, T>
{
public T Convert(ResolutionContext context)
{
var currentLanguage = MultilingualValueData.CurrentLanguage; //THIS IS THE [ThreadStatic] VARIABLE
if (currentLanguage == null) throw new InvalidOperationException("Please make sure to fill in CurrentLanguage");
MultilingualValue<T> sourceMultilingualValue = (MultilingualValue < T > )context.SourceValue;
T destinationValue = default(T);
if (sourceMultilingualValue != null)
{
destinationValue = sourceMultilingualValue.Value[currentLanguage.Value];
}
return destinationValue;
}
}
public static class MultilingualValueData
{
[ThreadStatic]
public static Language? CurrentLanguage;
}
I left out the configurations as I think they're unneccessary for this example. If you need them, I'll post them as well.
While this works, I find this workaround quite ugly. Is there any way to pass data through the ResolutionContext?
Just use the Map overload that takes a Action<IMappingOperationOptions>. You can add configuration elements to the Items property that are then passed to your ITypeConverter
public class CustomConverter : ITypeConverter<string, string>
{
public string Convert(ResolutionContext context)
{
return "translated in " + context.Options.Items["language"];
}
}
internal class Program
{
private static void Main(string[] args)
{
AutoMapper.Mapper.CreateMap<string, string>().ConvertUsing<CustomConverter>();
var result = AutoMapper.Mapper.Map<string, string>("value" , opt => opt.Items["language"] = "english");
Console.Write(result); // prints "translated in english"
Console.ReadLine();
}
}