How to check multiple properties on an object have the same condition? - c#

I have a pretty long and unwieldy method which takes in an object as a parameter, then checks every property against the same criteria (== "random") and performs a specific action against the property.
public void CreateRegistration(UserGroup user, int mobileLength, int passwordLength, int questionLength) {
if (user.Title == "random") {
title.ClickDropdown();
} else {
WebElementExtensions.ClickDropdown(title,user.Title);
}
if (user.Firstname == "random") {
firstName.SendKeys(GenerateData.GenerateRandomName());
} else {
firstName.SendKeys(user.Firstname);
}
if (user.Middlename == "random") {
middleName.SendKeys(GenerateData.GenerateRandomName());
} else {
firstName.SendKeys(user.Middlename);
}
etc....
Is it possible to somehow check all my properties against the same criteria together, then reduce my code so all the actions on the individual properties are within the same code block? so one code block for is = random and one for else.
Many thanks,

I prefer to use LINQ for this purpose usually:
private bool CheckAllProperties(UserGroup instance)
{
return instance.GetType().GetProperties()
.Where(c => c.GetValue(instance) is string)
.Select(c => (string)c.GetValue(instance))
.All(c => c== "random");
}
And then:
if (CheckAllProperties(user))
{
}

Related

Implementation of IEnumerable and IEnumerator in custom object, return the same data when called multiple times by LINQ with a different predicate

I wanted to be able to use LINQ queries on a custom object that does not use typical collections but nevertheless stores data in a sequential manner. The object is of type XTable that contains a collection of XRows and I have the following code that implements IEnumerable and IEnumerator.
public class EnumerableXTable : IEnumerable<XRow>
{
private readonly XTable _xTable;
public EnumerableXTable(XTable xTable)
{
_xTable=xTable;
}
IEnumerator<XRow> IEnumerable<XRow>.GetEnumerator()
{
return new XTableEnumerator(_xTable);
}
public IEnumerator GetEnumerator()
{
return new XTableEnumerator(_xTable);
}
}
public class XTableEnumerator : IEnumerator<XRow>
{
private readonly XTable _xTable;
private int _index = -1;
public XTableEnumerator(XTable xTable)
{
_xTable=xTable;
}
public void Dispose()
{
}
public bool MoveNext()
{
_index++;
if (_index == _xTable.Count) return false;
_xTable.Current.RecNo = _index;
return true;
}
public void Reset()
{
throw new NotImplementedException("IEnumerator Reset Method not implemented");
}
public XRow Current => _xTable.Current;
object IEnumerator.Current => Current;
}
public static EnumerableXTable AsEnumerable(this XTable xTable)
{
return new EnumerableXTable(xTable);
}
If I run the below code:
XTable t = GetXTable();
var xRow1 = t.AsEnumerable().First(xRow => xRow.Get<int>("CCCIntaleId") == 462);
var xRow2 = t.AsEnumerable().First(row => row.Get<int>("CCCIntaleId") == 465);
xRow1 and xRow2 are the exact same row, and according to the predicate, they should be different. If I set breakpoints, then when I break after the first statement, xRow1 has the correct value and if I break after the second statement, xRow2 has the correct value and now xRow1 is the value of xRow2. It looks like there is some form of deferred execution although I think that when calling First(), execution should be immediate. The following code returns the correct results on recNo1 and recNo2:
XTable t = GetXTable();
var xRow1 = t.AsEnumerable().First(xRow => xRow.Get<int>("CCCIntaleId") == 462);
int recNo1 = xRow1.RecNo;
var xRow2 = t.AsEnumerable().First(row => row.Get<int>("CCCIntaleId") == 465);
int recNo2 = xRow2.RecNo;
Furthermore, if I run the same code on a DataTable with the same structure as follows:
var row1 = datatable.AsEnumerable().First(row => row.Field<int>("CCCIntaleId") == 462);
var row2 = dd.AsEnumerable().First(row => row.Field<int>("CCCIntaleId") == 465);
the results I get are as expected. Is there anything wrong on my implementation of IEnumerator?
The solution was given in the comments. The problem was that _xTable.Current returns the same object everytime, with a different indexer. Thus, both xRow1 and xRow2 refer to the same object and at the end, both objects point to the values dictated by the indexer.

Getting compile time error while using lambda in C#

I am trying to use FirstOrDefault in my code but getting compile time error.
Cannot implicitly convert type Priority to bool
public class Priority
{
public string Name { get; set; }
public string Id { get; set; }
public string Default { get; set; }
}
public class ProcedureStatus
{
public string Id { get; set; }
public Priorities Priorities { get; set; }
}
public class Priorities
{
public List<Priority> Priority { get; set; }
}
foreach (Priority priority in status.Priorities.Priority)
{
if (priority.Default == "true" && grid.Priority == null)
{
grid.Priority = priority.Id;
grid.PriorityText = priority.Name;
SetPriority(gridRow);
break;
}
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id))
priority.Default = "true";
}
How to use FirstOrDefault in my scenario.
You are using status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) in an if clause.
The if clause is expecting an expression that returns a bool, but your expression returns a Priority.
Aside from that, it looks like the if clause is redundant, since you are iterating the properties via a foreach and trying to get the current item from the list you are already iterating. If you just want to iterate the list, you don't need the if clause.
The way you would typically use FirstOrDefault would be like this:
var priority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priorityId)`;
if (priority != null)
{
\\ ...
}
where priorityId is the ID of the priority you are looking for.
This does not seem useful inside you foreach loop though.
(Even after your question update, you still have the same if clause inside the foreach. It's just after an if/else now.)
The problem
The problem is not related to Lambda expressions (x => blablabla syntax) but related to what a specific function FirstOrDefault() returns and how to use it in an if-else-elseif scenario.
Analysis
The code you wrote could be written in two steps as:
if (priority.Default == "true" && grid.Priority == null)
{
// your if block
}
else
{
Priority firstPriority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id);
// Same exact error you got... Cannot implicitly convert type Priority to bool
if (firstPriority) {
priority.Default = "true";
}
}
Now it is more easy to understand what the problem is... if, else and else if statements need a logical expression to work. That can be made either using a bool variable or doing a check/evaluation that returns true/false.
Solution
There are many different ways to address the problem:
You could use a function that directly returns a boolean like Any(), that would be useful if you do not need to use the object matching the x => x.Id == priority.Id.
You could use FirstOrDefault() but changing your else if to convert it into something that return a logic expression. This would be useful if you need to later work with that element.
Using the Any() function
else if (status.Priorities.Priority.Any(x => x.Id == priority.Id))
{
priority.Default = "true"; // Dumb question, why the Default property is not of type bool???
}
Using the FirstOrDefault()
Note: you have already been given this option in other answers. Ergwun's answer and Braulio's answer so far.
As per the documentation of the function I linked and what its name suggests, if the FirstOrDefault() function does not find anything, it returns null. So you could check it whatever it returns is null or not.
This could be done in a couple of ways. Depending on if you need to later work with whatever the function returns or not.
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) != null)
{
priority.Default = "true";
}
or
if (priority.Default == "true" && grid.Priority == null)
{
// your if block
}
else
{
Priority firstPriority = status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id);
if (firstPriority != null) {
priority.Default = "true";
Console.WriteLine("The description of the priority if the Id XXXX is: " + firstPriority.Description);
}
}
Best way it's to compare if your object is not null after the research
foreach (Priority priority in status.Priorities.Priority)
{
if (grid.Priority == null)
{
grid.Priority = priority.Id;
grid.PriorityText = priority.Name;
break;
}
else if (status.Priorities.Priority.FirstOrDefault(x => x.Id == priority.Id) != null)
// You found something, do this.
}
Try it

Indexer with multiple return types

I'm using Indexers in my class to make searching through a list easier. However, I want to be able to return both a bool and an int. Not at the same time but determine whether it's a bool or an int and then return it.
public class uPermissions
{
private List<uPermission> permissions = new List<uPermission> ()
{
new uPermission ("canBuild", false),
new uPermission ("canClaim", false),
new uPermission ("canUnClaim", false),
new uPermission ("canInvite", false),
new uPermission ("canKick", false),
new uPermission ("canSetHome", false)
};
private List<uConstraint> constraints = new List<uConstraint> ();
public bool this[string index]
{
get
{
return permissions.Where (p => p.name == index).First ().allowed;
}
set
{
permissions.Where (p => p.name == index).First ().allowed = value;
}
}
public int this[string index]
{
get
{
return constraints.Where (c => c.name == index).First ().count;
}
set
{
constraints.Where (c => c.name == index).First ().count = value;
}
}
public bool exists (string permission)
{
var perm = permissions.Where (p => p.name.ToLower () == permission.ToLower ()).First ();
return (perm != null) ? true : false;
}
public void setAllTrue ()
{
foreach (uPermission p in permissions)
{
p.allowed = true;
}
}
public void setAllFalse ()
{
foreach (uPermission p in permissions)
{
p.allowed = false;
}
}
}
public class uConstraint
{
public string name;
public int count;
public uConstraint () { }
public uConstraint (string name, int count)
{
this.name = name;
this.count = count;
}
}
public class uPermission
{
public string name;
public bool allowed;
public uPermission () { }
public uPermission (string name, bool allowed)
{
this.name = name;
this.allowed = allowed;
}
}
That's my code. I saw something about templates while searching but I don't understand how it works or if it's even the right solution. If anyone can give some insight it would be greatly appreciated
C# will not allow you to distinguish overloads purely based on their return types (they must differ in at least one parameter type or type argument count).
You can create a generic method and use the type argument to distinguish between your two intentions. E.g.
class uPermissions {
public T GetAllowedOrCount<T>(string index) {
get {
if (typeof(T) == typeof(bool) {
return permissions.Where (p => p.name == index).First ().allowed;
} else if (typeof(T) == typeof(int) {
return constraints.Where (c => c.name == index).First ().count;
}
throw new InvalidOperationException("only bool and int are supported");
}
}
and then you'd call it with an explicit type argument, such as
var fooCount = uPermissions.GetAllowedOrCount<int>("foo")
var fooAllowed = uPermissions.GetAllowedOrCount<string>("foo")
Note that this solution would not work with the this indexer as C# does not support generic indexers.
I suppose though we agree that this does not sound like something you'd want to do. Your dispatch is now run-time as opposed to compile-time and you would certainly not gain type safety as
uPermissions.GetAllowedOrCount<double>("foo")
would also compile and blow up with a runtime exception.
To be honest I also would find it very confusing that the same (or overloaded) method returns/sets two totally different things (i.e. allowed vs count). I'd rather have two different methods for that or return a data structure (that has a getter for allowed/count) from a single method. In the latter case you could also use indexers if that is what you fancy.
The overload resolution mechanism in C# doesn't regard return values. You can't have two methods with the same name and argument, differing only in their return type.
Indexer is just a method (or two), so it follows the same rules. You can't have two indexers with the same arguments, differing only in their return type.
I suggest to use two different properties each containing a dictionary or some List-type instead. That way you could write something like this:
bool foo = uPermissionsInstance.Permissions["someName"];
int bar = uPermissionsInstance.Constraints["someOtherName"];
Alternatively there's a "hack" you could use, that works quite well:
Write a Class that has two implicit casts implemented. One for int and one for bool.
Return this class instead of the int or bool and set its internal value appropriately.
That way you can write the following. But this won't work with the setter!
bool foo = uPermissionsInstance["someName"];
int bar = uPermissionsInstance["someOtherName"];
Implementation:
public IntBoolValue this[string index]
{
get
{
// Here you need to check whether you can find an entry in permissions or in constraints. Then return the found value.
return new IntBoolValue(permissions.Where (p => p.name == index).First ().allowed);
}
}
// ------------------
internal struct IntBoolValue
{
internal int internalInt;
internal bool internalBool;
public IntBoolValue(int value) { this.internalInt = value; }
public IntBoolValue(bool value) { this.internalBool = value; }
public static implicit operator bool(IntBoolValue value)
{
return value.internalBool;
}
public static implicit operator int(IntBoolValue value)
{
return value.internalInt;
}
}

Alternative to switch with non-constant

I just learned that a switch statement can't use non-constant conditions. Which is fine and all, I get it. But does that really mean I have to make a big if-else block? It's so ugly I'm crying.
Some context: I'm doing a Unity project and I want to switch on the current animation state. A good way to check the current animation state is to compare hashes, which means I need to calculate the hashes for the animation state. After calculating them I want to switch on them. (Writing this I realized I can paste the resulting hash into a constant, but now I still want an answer)
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
switch (hash):
{
case state1:
//DoStuff
break;
case state2:
//Other stuff
break;
}
What's the best way to do this?
You can do this with a dictionary.
Try this:
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
var cases = new Dictionary<Func<bool>, Action>()
{
{ () => hash == state1, () => { /* Do stuff */} },
{ () => hash == state2, () => { /* Do other stuff */} },
};
cases
.Where(c => c.Key()) // find conditions that match
.Select(kvp => kvp.Value) //select the `Action`
.FirstOrDefault() // take only the first one
?.Invoke(); // Invoke the action only if not `null`
To make it a little more clean you could define a Switch class like this:
public class Switch : IEnumerable<Switch.Case>
{
private List<Case> _list = new List<Case>();
public void Add(Func<bool> condition, Action action)
{
_list.Add(new Case(condition, action));
}
IEnumerator<Case> IEnumerable<Case>.GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
public void Execute()
{
this
.Where(c => c.Condition())
.Select(c => c.Action)
.FirstOrDefault()
?.Invoke();
}
public sealed class Case
{
private readonly Func<bool> _condition;
private readonly Action _action;
public Func<bool> Condition { get { return _condition; } }
public Action Action { get { return _action; } }
public Case(Func<bool> condition, Action action)
{
_condition = condition;
_action = action;
}
}
}
Then the code looks like this:
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
var #switch = new Switch()
{
{ () => hash == state1, () => { /* Do stuff */} },
{ () => hash == state2, () => { /* Do other stuff */} },
};
#switch.Execute();
And if you write it like this it almost looks like a normal switch statement:
var #switch = new Switch()
{
{
() => hash == state1,
() =>
{
/* Do stuff */
}
},
{
() => hash == state2,
() =>
{
/* Do other stuff */
}
},
};
You can also use case guards and local functions like this:
bool HashMatches(int TargetHash) => hash == TargetHash;
switch (true):
{
case true when HashMatches(state1):
//DoStuff
break;
case true when HashMatches(state2):
//Other stuff
break;
}
Whether you can simplify it or not, it depends on the similarities between your "DoStuff", "Other Stuff", "Next Stuff", and "You other stuffs"
Suppose your Stuff "family members" are actually:
int stuffAction(int state){
int modified_state;
//do something on state and modified state
return modified_state;
}
Then, obviously you Stuffs can be simplified by using function, just as shown above. It can be simplified likewise as long as your Stuff have same function with different argument.
Also, if you Stuffs are in the form different functions but having the same input parameters, you can create Dictionary of delegates (see System.Collections.Generic.Dictionary<string, System.Delegate>) such that when you can call the Stuff you simply need to do
dic[state](input parameters here)
instead of using if-else or switch
There might be some possibilities where your code cannot be simplified further, but the bottom line is, as I said earlier, depend on the similarities between your Stuffs.
You can do it only with if-else if:
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
if (hash == state1) {
//DoStuff
}
else if (hash == state2) {
//Other stuff
}

Generic type sorting by nested properties

I have the following static class:
public static class SortFilter
{
public enum SortDirection { Ascending, Descending }
public static IEnumerable<TEntity> Sort<TEntity, TKey>(IEnumerable<TEntity> entities, Func<TEntity, TKey> sorter, SortDirection d)
{
if (SortDirection.Ascending == d)
{
return entities.OrderBy(sorter);
}
else
{
return entities.OrderByDescending(sorter);
}
}
public static IEnumerable<TEntity> Sort<TEntity>(IEnumerable<TEntity> entities, string sortParams)
{
string[] parameters = sortParams.Split('_');
if (parameters.Count() == 1 || parameters.Count() > 2)
{
return entities;
}
else
{
if (parameters[1] == "ascending")
{
return Sort(entities, x => GetPropertyValue(x, parameters[0]), SortDirection.Ascending);
}
else if (parameters[1] == "descending")
{
return Sort(entities, x => GetPropertyValue(x, parameters[0]), SortDirection.Descending);
}
else
{
return entities;
}
}
}
public static object GetPropertyValue(object obj, string name)
{
return obj == null ? null : obj.GetType()
.GetProperty(name)
.GetValue(obj, null);
}
}
I can call the Sort method on a List like this (the User class has Id and Name properties):
users = SortFilter.Sort(users, "Name_ascending");
users = SortFilter.Sort(users, "Id_ascending");
So far, so good: that will work just fine.
However, let's say my User class also has a UserGroup property and that I want to sort my User list by the Name of that UserGroup. This call will obviously fail:
users = SortFilter.Sort(users, "UserGroup.Name_ascending");
given that UserGroup.Name is not itself a Type (therefore GetPropertyValue method will throw an exception).
Is there a way to make a generic enough Sort function that will take a collection and sort it by any number of nested properties sent as an argument? I have several Views with table data that should be sorted by any column the user clicks, in ascending or descending order. Having sorting and filtering code within the controller seems very dirty.
Like always for string parameters for LINQ use DynamicLINQ:
using System.Linq.Dynamic;
//..
if (parameters[1] == "ascending" || parameters[1] == "descending")
{
return entities.AsQueryable()
.OrderBy(string.Format("{0} {1}", parameters[0], parameters[1]))
}
else
{
return entities;
}
Docs can be found here in LinqSamples/DynamicQuery/Dynamic Expressions.html.
Nested properties are supported of course.

Categories

Resources