I have a pretty specific problem.
I have a custom class with various properties of the same type and I have a method elsewhere which needs to run on the class and compare those properties. The method needs to be able to compare these properties, but is instructed to compare different ones depending on the situation.
As it stands, I have a switch which takes a string to determine which properties to compare:
switch(field)
{
case "int1":
if (myClass1.int1 < myClass2.int1)
{
//do something
}
break;
case "int2":
if (myClass1.int2 < myClass2.int2)
{
//do something
}
break;
}
Is there a way that I could just set a variable to refer to the property of the class which I want to refer which would allow just using the switch and have the code comparing the properties later? Something like this:
var referrer;
switch(field)
{
case "int1":
referrer = int1;
break;
case "int2":
referrer = int2;
break;
}
if (myClass1.referrer < myClass2.referrer)
{ //do something }
You could do this using a Func<T, int> approach, something like:
public class SomeClass
{
public int First { get; set; }
public int Second { get; set; }
}
var one = new SomeClass { First = 1, Second = 5 };
var two = new SomeClass { First = 5, Second = 1 };
Func<SomeClass, int> referrer = null;
switch (field)
{
case "first":
referrer = x => x.First;
break;
case "second":
referrer = x => x.Second;
break;
}
if (referrer(one) < referrer(two))
{
}
Of course, this assumes that you always want to compare int properties. Take a look here.
There is another way, if you want to avoid the switch completely, and is to use Reflection:
public class Program
{
public static void Main()
{
var one = new SomeClass { First = 1, Second = 5 };
var two = new SomeClass { First = 5, Second = 1 };
string field = "First";
if (GetValue(one, field) < GetValue(two, field))
{
Console.WriteLine("one is smaller than two");
}
else
{
Console.WriteLine("one is greater than two");
}
}
private static int GetValue(SomeClass someClass, string field) => Convert.ToInt32(typeof(SomeClass).GetProperty(field).GetValue(someClass));
}
public class SomeClass
{
public int First { get; set; }
public int Second { get; set; }
}
Related
I need to sort a list by any one of its properties, but i dont know which of these properties it will specifically be sorted on. The Main method below.
static void Main(string[] args)
{
Things<Something> something = new Things<Something>();
something.Add(new Something
{ Thing = "Apartment", Price = 1500000 });
something.Add(new Something
{ Thing = "Bed", Price = 10000 });
something.Add(new Something
{ Thing = "Lamp", Price = 600 });
something.Add(new Something
{ Thing = "Car", Price = 5000000 });
Console.WriteLine("\n\tStuff sorted by description");
something = something.SelectionSort("Thing");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.WriteLine("\n\tStock items sorted by value");
something = something.SelectionSort("Value");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.Write("\n\tPress any key to exit ...");
Console.ReadKey();
}
I have a struct
public struct Something
{
public string Thing { get; set; }
public decimal Price { get; set; }
}
And a generic container class called things
public class Things<T> : IEnumerable<T>
{
private List<T> lstItems;
public int Count { get { return lstItems.Count; } }
public Things() { lstItems = new List<T>(); }
public Things(List<T> items_) { lstItems = new List<T>(items_); }
public void Add(T item)
{
lstItems.Add(item);
}
public T this[int i]
{
get { return lstItems[i]; }
set { lstItems[i] = value; }
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new System.NotImplementedException();
}
public IEnumerator<T> GetEnumerator()
{
foreach (T item in lstItems)
yield return item;
}
}
An extensions class extends the generic container class
public static class ExtensionsClass
{
private static string SortFiield { get; set; }
private static object GetProperty<T>(T thing, string nameofProp)
{
return thing.GetType().GetProperty(nameofProp).GetValue(thing, null);
}
private static int Compare<T>(T x, T y)
{
IComparable propX = (IComparable)GetProperty(x, SortFiield);
IComparable propY = (IComparable)GetProperty(y, SortFiield);
return propX.CompareTo(propY);
}
public static Things<T> SelectionSort<T>(this Things<T> things, string SORTFIELD)
{
List<T> lsstt = new List<T>(things);
int iIndex;
T temporary;
SortFiield = SORTFIELD;
for (int i = 0; i < lsstt.Count - 1; i++)
{
iIndex = i;
for (int j = i + 1; j < lsstt.Count; j++)
{
string first = GetProperty(lsstt[j], SortFiield).ToString();
string second = GetProperty(lsstt[iIndex], SortFiield).ToString();
if (Compare(first, second) < 0)
iIndex = j;
}
temporary = lsstt[i];
lsstt[i] = lsstt[iIndex];
lsstt[iIndex] = temporary;
}
return new Things<T>(lsstt);
}
}
The problem i am encountering is that get property in the extension class returns null, but i know that the object i am trying to return exists. It is found by the "String first = ...." line but when getproperty is called from the Compare method then it returns null.
You are passing "first", "second" to Compare. In your case both of them are strings and not objects, you need to pass "lsstt[j]" and "lsstt[iIndex]" to it.
if (Compare(lsstt[j], lsstt[iIndex]) < 0)
iIndex = j;
How can I implement a switch case (or similar effect) in an expression body? I am creating a Model object (lets call it MyModel) and one of the fields is a recurrence field. The recurrence is based on the current day of the week (Monday's example is below). Basically I want to set the Weekly____ to be true. I was also thinking that potentially String.Format() would have something to support this, but I couldn't get it to work.
var my = new MyModel
{
Recurrence = new RecurrenceModel
{
WeeklyMonday = true //what it would be on a Monday
}
};
My attempt with switch case
var my = new MyModel
{
switch(DateTime.Today.DayOfWeek.ToString())
case "Monday":
Recurrence = new RecurrenceModel
{
WeeklyMonday = true
}
break;
default:
break;
};
My attempt with String.Format()
var my = new MyModel
{
Recurrence = new RecurrenceModel
{
String.Format("Weekly{0}", DateTime.Today.DayOfWeek.ToString()) = true
}
};
I'm guessing you're fairly new to C#?
What you need to do is something like this
var my = new MyModel
{
Recurrence = new RecurrenceModel
{
WeeklyMonday = DateTime.Today.DayOfWeek == DayOfWeek.Monday
}
};
In both of your attempts, you're not actually assigning the value to the property. Your code will not compile because it's not valid C#. You don't need a switch or a string.Format to achieve what you're after.
In my example, I'm assigning the result of DateTime.Today.DayOfWeek == DayOfWeek.Monday to the WeeklyMonday property on your model class
simonlchilds is right. The best way to do this is within the constructor of the class, evaluating the value of the current day to set which property to true.
I personally would do something like this.
class RecurrenceModel
{
public RecurrenceModel()
{
GetType().GetProperty("Weekly" + DateTime.Today.DayOfWeek).SetValue(this, true);
}
public bool WeeklyMonday { get; set; }
public bool WeeklyTuesday { get; set; }
public bool WeeklyWednesday { get; set; }
public bool WeeklyThursday { get; set; }
public bool WeeklyFriday { get; set; }
public bool WeeklySaturday { get; set; }
public bool WeeklySunday { get; set; }
}
That way, whenever this class is instantiated, it will automatically set whichever the day is to true and this is all you would need to do.
var my = new MyModel
{
Recurrence = new RecurrenceModel()
};
I have an interesting question, one I'm having difficulty searching for an answer on.
I have two IEnumerable collections of objects. The underlying objects are completely separate, BUT I can identify a shared key that should match. The collections are important, in that my "left" object is the "system of record", and the "right" object is representing a system I need to ensure matches the system of record.
Once they are matched, I need to perform CRUD operations on one side to bring the right side in line with the left side. For example, it would create a new item on the right side if one didn't exist, or update values, or delete if the item was missing on the left, but not the right.
The catch is, I have hundreds of these collections to match up, and the actual CRUD code is different.
I'd like to introduce some shared code where I can pass in both collections, the collection types (as probably generics), some kind of comparer, and some delegates of what operation to perform for CRUD.
If this code actually existed, it may look something like this
class Stuff
{
string Id {get; set;}
string Name {get; set;}
}
class Junk
{
string Id {get; set;}
string ShortName {get; set;}
}
IEnumerable<Stuff> myStuff = GetStuff();
IEnumerable<Junk> myJunk = GetJunk();
CrudComparer cc = new CrudComparer<Stuff, Junk>(myStuff, myJunk);
cc.Comparer = (leftObject, rightObject) => {
leftObject.Name == rightObject.Name
}
cc.CreateOperation = (newObject, rightCollection) => {
Junk j = new Junk();
j.Shortname = newObject.Name;
rightCollection.Add(j);
}
cc.UpdateOperation = (leftObject, rightObject) => {
rightObject.Shortname = leftObject.Name;
}
cc.DeleteOperation = (rightCollection, rightObject) => {
rightCollection.Remove(rightObject);
}
cc.Compare();
Has anyone ever seen code that does something like this? I'd hate to reinvent the wheel if I can grab something already done.
Thanks for any help!
--Michael
I got to thinking more about this, and realized what I knew about delgates and generics should be sufficient to solve this problem, so I got in LinqPad and had some fun. I haven't written any unit tests around this yet, so use at your own risk, but hopefully if you want to use this you understand the underlying concepts.
class Blah
{
public int ID { get; set; }
public string BlahName { get; set;}
}
class Bleh
{
public int ID { get; set; }
public string BlehName { get; set;}
}
class CrudComparer<TLeft, TRight>
{
private readonly ICollection<TLeft> _leftCollection;
private readonly ICollection<TRight> _rightCollection;
private readonly Comparer _compareOperation;
private readonly CreateOperation _createOperation;
private readonly UpdateOperation _updateOperation;
private readonly DeleteOperation _deleteOperation;
public delegate bool Comparer(TLeft leftItem, TRight rightItem);
public delegate void CreateOperation(TLeft leftItem, ICollection<TRight> rightCollection);
public delegate void UpdateOperation(TLeft leftItem, TRight rightItem);
public delegate void DeleteOperation(TRight rightItem, ICollection<TRight> rightCollection);
public CrudComparer(ICollection<TLeft> leftCollection, ICollection<TRight> rightCollection, Comparer compareOperation, CreateOperation createOperation, UpdateOperation updateOperation, DeleteOperation deleteOperation)
{
_leftCollection = leftCollection;
_rightCollection = rightCollection;
_compareOperation = compareOperation;
_createOperation = createOperation;
_updateOperation = updateOperation;
_deleteOperation = deleteOperation;
}
public void Compare()
{
foreach (TLeft leftItem in _leftCollection)
{
bool foundItem = false;
foreach (TRight rightItem in _rightCollection)
{
if (_compareOperation(leftItem, rightItem))
{
//these equal
foundItem = true;
}
}
if (foundItem == false)
{
_createOperation(leftItem, _rightCollection);
}
}
List<TRight> itemsToDelete = new List<TRight>();
foreach (TRight rightItem in _rightCollection)
{
bool foundItem = false;
foreach (TLeft leftItem in _leftCollection)
{
if (_compareOperation(leftItem, rightItem))
{
foundItem = true;
_updateOperation(leftItem, rightItem);
break;
}
}
if (!foundItem)
{
itemsToDelete.Add(rightItem);
}
}
foreach (TRight itemToDelete in itemsToDelete)
{
_deleteOperation(itemToDelete, _rightCollection);
}
}
}
void Main()
{
List<Blah> blahItems = new List<Blah>();
blahItems.Add(new Blah() { ID = 1, BlahName = "Blah" });
blahItems.Add(new Blah() { ID = 2, BlahName = "ABC" });
blahItems.Add(new Blah() { ID = 34, BlahName = "XYZ" });
blahItems.Add(new Blah() { ID = 6442, BlahName = "123" });
List<Bleh> blehItems = new List<Bleh>();
blehItems.Add(new Bleh() { ID = 2, BlehName = "12345"});
blehItems.Add(new Bleh() { ID = 6, BlehName = "43232"});
blehItems.Add(new Bleh() { ID = 77, BlehName = "BlahBlah"});
blehItems.Add(new Bleh() { ID = 2334, BlehName = "ZYX"});
CrudComparer<Blah, Bleh>.Comparer compareOperation = (leftObject, rightObject) =>
{
return leftObject.ID == rightObject.ID;
};
CrudComparer<Blah, Bleh>.CreateOperation createOperation = (leftObject, rightCollection) =>
{
rightCollection.Add(new Bleh() { ID = leftObject.ID });
};
CrudComparer<Blah, Bleh>.UpdateOperation updateOperation = (leftObject, rightObject) =>
{
rightObject.BlehName = leftObject.BlahName;
};
CrudComparer<Blah, Bleh>.DeleteOperation deleteOperation = (rightObject, rightCollection) =>
{
rightCollection.Remove(rightObject);
};
CrudComparer<Blah, Bleh> cc = new CrudComparer<Blah, Bleh>(blahItems, blehItems, compareOperation, createOperation, updateOperation, deleteOperation);
cc.Compare();
}
I have a List containing multiple Lists that contain typed objects themselves:
List<List<Activity>> SortActivities
An object of type Activity looks like this:
public class Activity
{
public DateTime Date { get; set; }
public string ProjectnumberUnformatted { get; set; }
public int Year
{
get
{
return Date.Year;
}
}
public int Month
{
get
{
return Date.Month;
}
}
public string MonthYear
{
get
{
return Month + " / " + Year;
}
}
public string Customer
{
get
{
return ProjectnumberUnformatted.Split('/')[0];
}
}
public string ProjectnumerFormatted
{
get
{
return ProjectnumberUnformatted.Split('/')[2];
}
}
public string MonthString
{
get
{
switch (Month)
{
case 1:
return "Januar";
case 2:
return "Februar";
case 3:
return "März";
case 4:
return "April";
case 5:
return "Mai";
case 6:
return "Juni";
case 7:
return "Juli";
case 8:
return "August";
case 9:
return "September";
case 10:
return "Oktober";
case 11:
return "November";
case 12:
return "Dezember";
default:
return "Invalid";
}
}
}
public string Start { get; set; }
public string Pause { get; set; }
public string End { get; set; }
public string Description { get; set; }
public string Comment { get; set; }
}
At program start, I have an object List<Activity> that contains unsorted activities. However, each activity should be sorted by it's project number. So I need to implement a method that sorts each activity from the List<Activity> object into it's own List<Activity> with the project number as the sorting argument. Then the resulting Lists are put into List<List<Activity>>.
I just need a basic flowchart if possible with a simple algorithm that does this job as I honestly have no idea how to start.
It sounds like you actually want a dictionary, where the key is the project number and the value is a list of activities. Sounds like an ideal job for LINQ:
List<Activity> activities = new List<Activity>
{
new Activity { ProjectnumberUnformatted = "abc" },
new Activity { ProjectnumberUnformatted = "def" },
new Activity { ProjectnumberUnformatted = "abc" },
new Activity { ProjectnumberUnformatted = "abc" },
new Activity { ProjectnumberUnformatted = "def" },
new Activity { ProjectnumberUnformatted = "ghi" },
new Activity { ProjectnumberUnformatted = "def" },
};
Dictionary<string, List<Activity>> activitiesKeyedOnProjectNumber = (
from activity in activities
group activity by activity.ProjectnumberUnformatted into grouped
select new { key = grouped.Key, value = grouped.ToList() }
).ToDictionary(
keySelector: x => x.key,
elementSelector: x => x.value
);
You do not want to sort objects, you want to group them.
What you need to do is to pass trough all elements in collection and assign each of them to group with correct identifier.
Dictionary<key,List<object>> would be better choice for data structure in such case.
Dictionary<string, List<ISortableObject>> Sort(List<ISortableObject> items)
{
var result = new Dictionary<string, List<ISortableObject>>();
foreach(var item in items)
{
if (!result.ContainsKey(item.SortingKey))
{ result[item.SortingKey]=new List<ISortableObject>(); }
result[item.SortingKey].Add(item);
}
}
OK thanks for all the answers. I looked into LINQ a little and came up with a really simple statement that served my purpose:
var groupedActivities = activities.GroupBy(p => p.ProjectnumberUnformatted);
with this, I get an enumeration containing other enumerations of typed Activity objects and can then iterate through those sub-enumerations and do what I need to do.
I have the following object and I want a dictionary to conditionally determine if there is a duplicate. For example, in one dictionary I only care about two properties being unique for my key. In a second dictionary, I want all the properties being unique for the key.
Question 1:
What interfaces should I override to accomplish this? (e.g. GetHashCode, IEqualityComparer, equals operator)
Question 2:
What should I do if I change a property that ultimately changes the value of the key? This is probably more relevant if I do an Dictionary since .NET framwork somehow handles this for me, but I never thought about it.
Code
public class EventData : IEqualityComparer<EventData>
{
public string ComputerName { get; set; }
public Guid? CategoryName { get; set; }
public string LogName { get; set; }
public int EventID { get; set; }
public long? EventUniqueTracker { get; set; }
public DateTime LastQueryDate { get; set; }
public DateTime? DateOfRecord { get; set; }
//public int QueryCount { get; set; }
public int QueryCount = 0 ;//
public string zData { get; set; }
public EventData(string computerName, Guid? categoryName, string logName, int eventID, long? eventUniqueTracker, int queryCount)
{
ComputerName = computerName;
CategoryName = categoryName;
LogName = logName;
EventID = eventID;
EventUniqueTracker = eventUniqueTracker;
LastQueryDate = DateTime.Now;
QueryCount = queryCount;
}
public EventData()
{
}
public override int GetHashCode()
{
return GetHashCode(HashType.ZCompCatLogEventAllData);
}
public object GetString(HashType hType)
{
switch (hType)
{
case HashType.AComputerName:
return ComputerName;
break;
case HashType.BCompAndCat:
return new { A = ComputerName, B = CategoryName };
break;
case HashType.CCompCatLog:
return new { A = ComputerName, B = CategoryName, C = LogName };
break;
case HashType.DCompCatLogEvent:
return new { A = ComputerName, B = CategoryName, C = LogName, D = EventID };
break;
case HashType.ECompCatLogEventUserDefined1:
case HashType.FCompCatLogEventUserDefined2:
case HashType.ZCompCatLogEventAllData:
return new { A = ComputerName, B = CategoryName, C = LogName, D = EventID, E = EventUniqueTracker };
default:
break;
}
return new object { };
}
public int GetHashCode(HashType hType)
{
return GetString(hType).GetHashCode();
return 1;
}
public override string ToString()
{
return ComputerName + " " + CategoryName + " " + LogName + " " + EventID + " " + EventUniqueTracker;
}
public bool Equals(EventData x, EventData y)
{
return x.ComputerName == y.ComputerName &&
x.CategoryName == y.CategoryName &&
x.LogName == y.LogName &&
x.EventID == y.EventID &&
x.EventUniqueTracker == y.EventUniqueTracker;
}
public int GetHashCode(EventData obj)
{
EventData ci = (EventData)obj;
// http://stackoverflow.com/a/263416/328397
return new { A = ci.ComputerName, B = ci.CategoryName, C = ci.LogName, D = ci.EventID, E = ci.EventUniqueTracker }.GetHashCode();
}
}
It sounds like you should be implementing IEqualityComparer<EventData> - but not within EventData itself. Create two separate implementations - one for the first notion of equality, and one for the second. Then create your dictionaries as:
var first = new Dictionary<EventData, string>(new PartialDataEqualityComparer());
var second = new Dictionary<EventData, string>(new FullDataEqualityComparer());
Or perhaps you want to treat the second case as the "natural" equality for EventData, in which case you could make EventData implement IEquatable<EventData> and not specify a comparer when creating the second dictionary.
Basically, you implement IEquatable<T> to say "an instance of this type is capable of comparing itself against an instance of T" whereas you implement IEqualityComparer<T> to say "an instance of this type is capable of comparing any two instances of T".
What should I do if I change a property that ultimately changes the value of the key?
You're stuffed, basically. You won't (or at least probably won't) be able to find that key again in your dictionary. You should avoid this as carefully as you possibly can. Personally I usually find that classes which are good candidates for dictionary keys are also good candidates for immutability.