Using TryParse for Setting Object Property Values - c#

I'm currently refactoring code to replace Convert.To's to TryParse.
I've come across the following bit of code which is creating and assigning a property to an object.
List<Person> list = new List<Person>();
foreach (DataRow row in dt.Rows)
{
var p = new Person{ RecordID = Convert.ToInt32(row["ContactID"]) };
list.Add(p);
}
What I've come up with as a replacement is:
var p = new Person { RecordID = Int32.TryParse(row["ContactID"].ToString(), out RecordID) ? RecordID : RecordID };
Any thoughts, opinions, alternatives to what I've done?

Write an extension method.
public static Int32? ParseInt32(this string str) {
Int32 k;
if(Int32.TryParse(str, out k))
return k;
return null;
}

I'd use an alternative implementation TryParse which returns an int?:
public static int? TryParseInt32(string x)
{
int value;
return int.TryParse(x, out value) ? value : (int?) null;
}
Then you can write:
var p = new Person { RecordID = Helpers.TryParseInt32(row["ContactID"].ToString()) ?? 0 };
(Or use a different default value, if you want - either way it'll be visible in your code.)

I suggest separate the TryParse part from initializer. It will be more readable.
int recordId;
Int32.TryParse(row["ContactID"].ToString(), out recordID)
foreach (DataRow row in dt.Rows)
{
var p = new Person{ RecordID = recordId };
list.Add(p);
}

private static void TryToDecimal(string str, Action<decimal> action)
{
if (decimal.TryParse(str, out decimal ret))
{
action(ret);
}
else
{
//do something you want
}
}
TryToDecimal(strList[5], (x) => { st.LastTradePrice = x; });
TryToDecimal(strList[3], (x) => { st.LastClosedPrice = x; });
TryToDecimal(strList[6], (x) => { st.TopPrice = x; });
TryToDecimal(strList[7], (x) => { st.BottomPrice = x; });
TryToDecimal(strList[10], (x) => { st.PriceChange = x; });

Related

Shorten Code by accessing Dictionary with if

I have the following code
Dictionary<string, string> changesDictionary = new Dictionary<string, string>();
if (changesDictionary.ContainsKey("field1"))
{
resultObject.field1 = changesDictionary["field1"];
}
if (changesDictionary.ContainsKey("field2"))
{
resultObject.field2 = changesDictionary["field2"];
}
if (changesDictionary.ContainsKey("field3"))
{
resultObject.field3 = changesDictionary["field3"];
}
which has 4 lines for a potential assignment. I'm wondering if there is a way to write it shorter.
I've tried the ternary operator which makes one line but it's harder to read.
resultObject.field1 = changesDictionary.ContainsKey("field1") ? changesDictionary["field1"] : resultObject.field1;
You could always do something like this. It's more verbose to start, but if you have lots of properties then it might pay off:
var fields = new (string key, Action<ResultObject, string> setter)[]
{
("field1", (x, val) => x.field1 = val),
("field2", (x, val) => x.field2 = val),
("field3", (x, val) => x.field3 = val),
};
foreach (var (key, setter) in fields)
{
if (changesDictionary.TryGetValue(key, out var field))
{
setter(resultObject, field);
}
}
Another option is something like this:
// A local function which captures 'resultObject' and 'changesDictionary'
void Set(string key, Action<ResultObject, string> setter)
{
if (changesDictionary.TryGetValue(key, out var field))
{
setter(resultObject, field);
}
}
Set("field1", (x, val) => x.field1 = val);
Set("field2", (x, val) => x.field2 = val);
Set("field3", (x, val) => x.field3 = val);
Otherwise, if you're prepared to change your style slightly, you can do this:
if (changesDictionary.TryGetValue("field1", out var field1)) resultObject.field1 = field1;
if (changesDictionary.TryGetValue("field2", out var field2)) resultObject.field2 = field2;
if (changesDictionary.TryGetValue("field3", out var field3)) resultObject.field1 = field3;
Using a local function:
void SetField(string fieldName, Action<string> updater)
{
if (changesDictionary.TryGetValue(fieldName, out string fieldValue))
{
updater(fieldValue);
}
}
SetField("field1", f => resultObject.field1 = f);
SetField("field2", f => resultObject.field2 = f);
SetField("field3", f => resultObject.field3 = f);
Price to pay = readability--
Line count = 11 instead of 13
Using a local function + reflection (provided fieldx are public properties):
void SetField(string fieldName)
{
if (changesDictionary.TryGetValue(fieldName, out string fieldValue))
{
PropertyInfo propertyInfo = resultObject.GetType().GetProperty(fieldName);
propertyInfo.SetValue(resultObject, fieldValue);
}
}
SetField("field1");
SetField("field2");
SetField("field3");
Price to pay = performance--
Line count = 12 instead of 13, but if you have 20 fields to update:
for (int i = 1; i <= 20; i++)
{
SetField($"field{i}");
}
Much shorter
Assuming (given the lowercase names for the field fields) that field1, field2 and field3 are actually fields rather than properties, then you can write a local function to simplify the code as follows:
Dictionary<string, string> changesDictionary = new Dictionary<string, string>();
void update(ref string field, string key)
{
if (changesDictionary.TryGetValue(key, out var value))
field = value;
}
update(ref resultObject.field1, "field1");
update(ref resultObject.field2, "field1");
update(ref resultObject.field3, "field1");
Note that will NOT work if field1 etc are actually properties, because of course you can't use ref with a property.
public static class DictionaryExtensions
{
public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
if (dictionary.TryGetValue(key, out value))
return value;
return defaultValue;
}
}
. . .
resultObject.field1 = changesDictionary.GetOrDefault("field1", resultObject.field1);
resultObject.field2 = changesDictionary.GetOrDefault("field2", resultObject.field2);
resultObject.field3 = changesDictionary.GetOrDefault("field3", resultObject.field3);
If your object has FIELDS not PROPERTIES, u can use just TryGetValue to field like this
changesDictionary.TryGetValue(nameof(ResultObject.field1), out resultObject.field1);
full example:
using System;
using System.Collections.Generic;
namespace ConsoleApp27
{
internal class Program
{
private static void Main(string[] args)
{
var resultObject = new ResultObject();
var changesDictionary = new Dictionary<string, string>();
changesDictionary.Add(nameof(ResultObject.field1), "q1");
changesDictionary.Add(nameof(ResultObject.field2), "q2");
changesDictionary.Add(nameof(ResultObject.field3), "q3");
changesDictionary.Add(nameof(ResultObject.field4), "q4");
changesDictionary.TryGetValue(nameof(ResultObject.field1), out resultObject.field1);
changesDictionary.TryGetValue(nameof(ResultObject.field2), out resultObject.field2);
changesDictionary.TryGetValue(nameof(ResultObject.field3), out resultObject.field3);
changesDictionary.TryGetValue(nameof(ResultObject.field4), out resultObject.field4);
Console.WriteLine(resultObject.field1);
Console.WriteLine(resultObject.field2);
Console.WriteLine(resultObject.field3);
Console.WriteLine(resultObject.field4);
Console.ReadLine();
}
public class ResultObject
{
public string field1;
public string field2;
public string field3;
public string field4;
}
}
}
output:
q1
q2
q3
q4

Add values from one IEnumerable<Type1> to other IEnumerable<Type2>

Let's say that we have two object types:
class Type1
{
public int Value {get;set;}
}
class Type2
{
public int Val {get; set;}
}
And we have two IEnumerable's for them:
IEnumerable<Type1> type1col;
IEnumerable<Type2> type2col;
What I want to have: each of type1col elements Value property value would have adequate type2col Val property value added.
We can say that both IEnumerables will have the same length always.
For now I am using this:
for (int i = 0; i < type1col.Count(); i++)
{
type1col.ElementAt(i).Value += type2col.ElementAt(i).Val;
}
but is there any better (faster & shorter) approach to do the same?
You can use IEnumerable.Zip:
var type1Col = type1Col.Select(x => x.Value)
.Zip(type2Col.Select(x => x.Value), (x, y) => x + y)
.Select(x => new Type1 { Value = x });
But as you allready have simple lists you can also use a classic loop and use indexers instead of IEnumerable.ElementAt:
for(int i = 0; i < type1Col.Count; i++)
{
type1Col[i].Value += typeo2Col[i];
}
Enumerating both together would be faster
[Benchmark]
public static void Enumerator()
{
using (var enumerator1 = Type1S.GetEnumerator())
{
using (var enumerator2 = Type2S.GetEnumerator())
{
while (enumerator1.MoveNext() && enumerator2.MoveNext())
{
enumerator1.Current.Value += enumerator2.Current.Val;
}
}
}
}
If you want to do an in-place modification of the elements of a sequence rather than having the overhead of creating a new sequence using Zip() you could do something like this:
public static void Combine<T1, T2>(IEnumerable<T1> target, IEnumerable<T2> modifyier, Action<T1, T2> modify)
{
using (var seq1 = target.GetEnumerator())
using (var seq2 = modifyier.GetEnumerator())
{
while (seq1.MoveNext() && seq2.MoveNext())
{
modify(seq1.Current, seq2.Current);
}
}
}
Which you would use like this:
IEnumerable<Type1> typecol1 = new List<Type1>{new Type1{Value = 1 }, new Type1 { Value = 2 } };
IEnumerable<Type2> typecol2 = new List<Type2>{new Type2{Val = 3}, new Type2{ Val = 4 } };
Combine(typecol1, typecol2, (type1, type2) => type1.Value += type2.Val);
foreach (var item in typecol1)
{
Console.WriteLine(item.Value);
}

Reflection to Filter List<T>

I am new to Reflection so please excuse my noob question. How can I create a Method that takes two Parameters, a Generic List and a String and then finds all items in that List where any property value matches the string.
So for example we have an object with 3 properties, I pass a list of this object to the method and a search string and it returns back a list of objects where any of the properties may contain the search string.
I can do like this :
var temp = list.AsQueryable().Where("SomeField == 1").Select("it");
But how can I make this method Generic so I can pass any List of Objects to it ?
Thanks in advance...
If you are using Dynamic Linq, try this
public static IEnumerable<T> Filter<T>(IEnumerable<T> source, string searchStr)
{
var propsToCheck = typeof (T).GetProperties().Where(a => a.PropertyType == typeof(string));
var filter = propsToCheck.Aggregate(string.Empty, (s, p) => (s == string.Empty ? string.Empty : string.Format("{0} OR ", s)) + string.Format("{0} == #0", p.Name));
var filtered = source.AsQueryable().Where(filter, searchStr);
return filtered;
}
Use Type.GetProperties() to get all the properties of an object. Use PropertyInfo.GetValue() to get the value of a given property in a given object. You need to figure out how you want a match your string to a DateTime, to numbers, or to other complex objects. Put it all into a function like bool IsMatch(this object obj, string val). Then you can filter your list like list.Where(x => x.IsMatch("something")).
Here you go mate:
private static void Main(string[] args)
{
var list = new List<object> {new {prop1 = "A", prop2 = "B"},new {prop3 = "B", prop4 = "C"}};
var subList = SearchForStringInProperties(list, "C");
}
private static IEnumerable<object> SearchForStringInProperties(IEnumerable<object> list, string searchString)
{
return from obj in list where FindStringInObjProperties(obj, searchString) select obj;
}
private static bool FindStringInObjProperties(object obj, string searchString)
{
return obj.GetType().GetProperties().Any(property => obj.GetType().GetProperty(property.Name).GetValue(obj).ToString().Equals(searchString));
}
If you just want to match the properties with same type as your argument, this extension method can help,
public static class ListExtensions
{
public static IEnumerable<T> MatchWithAnyProperty<T, TK>(this IEnumerable<T> list, TK value)
{
var argType = typeof (TK);
var properties = typeof(T).GetProperties().Where(x => x.PropertyType.IsAssignableFrom(argType));
return list.Where(item => properties.Any(prop =>
{
var propertyValue = prop.GetValue(item, null);
if (value == null)
return propertyValue == null;
return propertyValue.Equals(value);
}));
}
}
This can be used like,
var items = new[]
{
new
{
Name = "Test",
Age = 20,
Test=25
},
new
{
Name = "Hello",
Age = 10,
Test=15
},
new
{
Name = "T2gdhest",
Age = 14,
Test=20
},
new
{
Name = "hai",
Age = 33,
Test=10
},
new
{
Name = "why not",
Age = 10,
Test=33
},
};
var match= items.MatchWithAnyProperty(10);
foreach (var item in match)
{
Console.WriteLine(item.Name);
}
Console.ReadKey();
And there is the old way ...
public static IList<T> MyMethod<T>(IList<T> myList, string filter)
{
if (myList == null) return null;
if (filter == null) return myList;
var tfilter = filter.GetType();
var properties = typeof(T).GetProperties().Where(x => x.PropertyType.FullName == typeof(string).FullName);
if (!properties.Any()) return null;
var res = new List<T>();
foreach(var el in myList)
{
foreach(var p in properties)
{
if ((string)p.GetValue(el) == filter)
{
res.Add(el);
break;
}
}
}
return res;
}

LINQ: Sort a list depending on parameter

I have a LINQ to object query to select all the persons that are above 20 years old
IEnumerable<Object> result = null;
result = (from person in AllPersons.ToList()
where person.age > 20
select new
{
FirstName= person.FirstName,
LastName= person.LastName,
Email= person.Email,
PhoneNumber= person.PhoneNumber
});
return result;
I have a parameter string SortProperty I want to use to sort the result based on the property.
So for example if SortProperty="FirstName" I want to sort the result based on the first name.
I tried to do the following:
return result.OrderBy(x => x.GetType().GetProperty(SortProperty));
but it did not work
any idea how to do it?
PS: I don't want to test all the possibilities, and do a if-else on each, or a case switch. I'm looking for an efficient way to do this
Thanks
Check out the Dynamic Linq Extensions Libraries...
It has extension Methods which accept strings instead of Properties.
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Since your SortProperty is already a string you could do
var result = (from person in AllPersons.ToList()
where person.age > 20
select new
{
FirstName= person.FirstName,
LastName= person.LastName,
Email= person.Email,
PhoneNumber= person.PhoneNumber
}
).OrderBy(SortProperty);
return result;
Also, depending on what AllPersons is, it might not make sense to Enumerate that by calling ToList() until the end. e.g.
var result = (from person in AllPersons
...
).OrderBy(SortProperty).ToList();
Try
return result.OrderBy(x => x.GetType().GetProperty(SortProperty).GetValue(x, null));
return result.OrderBy( x => TypeHelper.GetPropertyValue( x, sortProperty ) )
.ToList();
I'm using something like this :
var sortExpression = #"A,C";
var expressions = sortExpression.Split(new[] { ',' });
var cmpPredicates = new Dictionary<string, Func<Person, Person, int>>(3);
cmpPredicates.Add(#"A", (x, y) => x.A.CompareTo(y.A));
cmpPredicates.Add(#"B", (x, y) => x.B.CompareTo(y.B));
cmpPredicates.Add(#"C", (x, y) => x.C.CompareTo(y.C));
cmpPredicates.Add(#"Default", (x, y) => x.Id.CompareTo(y.Id));
var currentPredicates = new Func<Person, Person, int>[expressions.Length + 1];
for (int i = 0; i < expressions.Length; i++)
{
currentPredicates[i] = cmpPredicates[expressions[i]];
}
// Default sort order
currentPredicates[currentPredicates.Length - 1] = cmpPredicates[#"Default"];
persons.Sort((x, y) =>
{
var cmp = 0;
var index = 0;
while (cmp == 0 && index < currentPredicates.Length)
{
cmp = currentPredicates[index++](x, y);
}
return cmp;
});
where the Person class has the following definition
public class Person
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public long Id { get; set; }
public Person()
{
this.A = string.Empty;
this.B = string.Empty;
this.C = string.Empty;
}
}
The main benefit is the multiproperty support. With additional checks(duplicates & exist & predicate limit) is can be user provided.

In C#, what's the best way to search a list of a class by one of the class's members?

Say I have a class that looks something like this:
class SomeClass {
int m_member;
public int Member {
get { return m_member; }
set { m_member = value; }
}
}
And somewhere else, I have a list of type List<SomeClass> list.
If I want to search the list for a particular instance of the class, I can just do
int index = list.IndexOf(someInstance);
But if I want to search the list by Member, I have to do this:
int index = -1;
for (int i = 0; i < list.Count; i++) {
if (list[i].Member == someMember) {
index = i;
break;
}
}
Is there a better way to do this?
int index = list.FindIndex(m => m.Member == someMember);
If you can use Linq
SomeClass aClasss = list.FirstOrDefault(item => item.Member == someMember);
You can have an extended search method(using reflection) for the list like below where property name and search value are input parameters.
public static List<T> SearchList<T>(this List<T> list, string PropertyName, string SearchValue)
{
return list.Select(item =>
new
{
i = item,
Props = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
})
.Where(item => item.Props.Any(p =>
{
var val = p.GetValue(item.i, null);
return val != null
&& (p.Name.ToLower() == PropertyName.ToLower() || string.IsNullOrEmpty(PropertyName))
&& (val.ToString().ToLower().Contains(SearchValue.ToLower()) || string.IsNullOrEmpty(SearchValue));
}))
.Select(item => item.i)
.ToList();
}
calling:
List<Employee> employees = new List<Employee>();
var searchedEmployees = data.SortList(serachProperty, searchValue);

Categories

Resources