C# Generics Efficiency, a better way to do this - c#

Ok, lets say I have classes such as the following:
public class KPIObject<T> //<--This class where T is the following classes
{
public List<T> Data { get; set; }
public string Caption { get; set; }
}
public class KPICycleCountAccuracyData //<--There are 20 of these with different names and values
{
public string Facility { get; set; }
public string CCAdjustedCases { get; set; }
public string TotalCases { get; set; }
public string CCAdjustedPercent { get; set; }
}
Then I have:
public List<ReportData>> ProcessAccountReport(GetAccountReport request)
{
var data = new List<ReportData>();
ProcessKPI(data, request.KPICycleCountAccuracy, "KPICycleCountAccuracy"); //<-- 20 of these
return data;
}
Here is the ProcessKPI method:
private static void ProcessKPI<T>(List<ReportData> data, ICollection<KPIObject<T>> items, string name)
{
if (items == null || items.Count <= 0) return;
foreach (var item in items)
{
if (item.Data == null || item.Data.Count <= 0) continue;
var temp = new List<object>();
temp.AddRange((IEnumerable<object>)item.Data);
data.Add(new ReportData { Data = temp, Name = name, Title = item.Caption });
}
}
All of this works and compiles correctly, I am just wondering if this is the most efficient way of doing this.
Thanks.
EDIT
I changed process KPI to this:
private static void ProcessKPI<T>(ICollection<ReportData> data, ICollection<KPIObject<T>> items, string name)
{
if (items == null || items.Count <= 0) return;
foreach (var item in items.Where(item => item.Data != null && item.Data.Count > 0))
{
data.Add(new ReportData { Data = (IEnumerable<object>)item.Data, Name = name, Title = item.Caption });
}
}

Couple of comments
There is no need to make data a ref parameter in ProcessKPI. A ref parameter is only meaningful for a class type in C# if you actually assign to it. Here you're just modifying the object so ref doesn't by you anything except awkward call syntax
Even though Count is signed it won't ever return a negative value.
I would prefer (IEnumerable<object>)item.Data over the as IEnumerable<object> version. If the latter fails it will result in an ArgumentNullException when really it's a casting issue.

Speed
Assuming you are talking about computational efficiency (i.e. speed), there are two operations that you might be able to improve:
First, you create a copy of the item.Data in the temp variable. When you know that the resulting ReportData will never be modified, you may use the item.Data directly, forgoing the expensive copy operation.
data.Add(new ReportData {
Data = (IEnumerable<object>)item.Data,
Name = name,
Title = item.Caption });
Second, converting to IEnumerable<object> will probably cause unnecessary boxing/unboxing at a later point. See if it makes sense for your application to add a generic type parameter to ReportData, so you may instantiate it as new ReportData<KPIObject>(). That way the compiler may do a better job of optimizing the code.
Memory
By implementing your solution using continuations you may be able to process one ReportData element at a time instead of all at once, thereby reducing the memory footprint. Have a look at the yield statement to see how to impelement such an approach.
Other
For futher code quality improvements, JaredPar's answer offers some exellent advice.

Related

How to Convert following code (foreach and if) into linq in c#?

How to Convert the below for each to Linq and if possible include the If statement into the Linq also.?
public class InvalidDataType
{
public string ViewName { get; set; }
public string ControlName { get; set; }
public string DataValue { get; set; }
}
foreach (InvalidDataType invalidField in DataObjectManager.GetInvalidFields())
{
if (invalidField.ControlName == "tbMCBNumber")
{
fieldToRemove = invalidField;
break;
}
}
if (fieldToRemove != null)
{
DataObjectManager.GetInvalidFields().Remove(fieldToRemove);
}
This is the code I tried
DataObjectManager.GetInvalidFields().Where(x => x.ControlName == "tbMCBNumber").Remove();
Where just returns a new collection, it doesn´t modifiy the existing one. That´s what the Q in LINQ stands for: query. This means linq isnt designed and therefor not really good when modifying collections. This is whyt you shouldn´t use LINQ when modifying the elements within your collections.
If your GetInvalidFields-methods returns a List<T> you can do the following:
DataObjectManager.GetInvalidFields().RemoveAll(x => x.ControlName == "tbMCBNumber");
This however isn´t LINQ, it´s just a method for ICollection<T>, which List<T> implements.
Alternativly you could use a single for-loop that couints backwards in order to remove some items from it:
var list = DataObjectManager.GetInvalidFields();
for(int i = list.Count - 1; i >= 0; i--)
{
if(list[i].ControlName == "tbMCBNumber").Remove(list[i]);
}
However this assumes you even can modify the underlying collection that GetInvalidFields returns. If that method returns something that can´t be modified at all like a ReadOnlyCollection or just en iterator there´s no way to remove items from that.

c# how to check if queue contains object property with a specific value?

I want to get Boolean value if queue contains object having particular value in the properties.
e.g)
public class Order
{
public string orderType { get; set; }
public string sCode { get; set; }
public int iNum { get; set; }
...omit...
}
Queue<Order> queueSendOrder = new Queue<Order>();
Then, how to check if Queue contains or not if contains any object having sCode="Code1", iNum=1?
Thank you.
Using the Linq Any() extension method, this is quite simple:
var containsCode1 = queueSendOrder.Any(o => o.sCode == "Code1");
var containsNum1 = queueSendOrder.Any(o => o.iNum == 1);
Or both:
var containsCode1AndNum1 = queueSendOrder.Any(o =>
o.sCode == "Code1"
&& o.iNum == 1);
Side note: It's considered bad practice these days to use Hungarian notation to denote types. So sCode should really just be Code and iNum would be Num (though I would choose a better name than that)

How can I efficiently compare the properties of two large lists of objects in C#?

I have a dataset of two lists of objects, which has an ID that will be consistent in both lists but other properties that may or may not be different. How can I most efficiently retrieve the ones that are different based on one or more properties?
My usual approach has been something along the lines of this. My object is set up like:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool IsEqual(Person other)
{
if (Name != other.Name)
{
return false;
}
if (Age != other.Age)
{
return false;
}
return true;
}
}
Where the IsEqual comparator is used to compare it to some equivalent object.
And then my method for finding modified people is like:
public static List<Person> FindModifiedPeople(List<Person> listA, List<Person> listB)
{
var modifiedPeople = new List<Person>();
foreach (var personA in listA)
{
var matchingPerson = listB.FirstOrDefault(e => e.ID == personA.ID);
if (matchingPerson == null)
{
continue;
}
if (!personA.IsEqual(matchingPerson))
{
modifiedPeople.Add(personA);
}
}
return modifiedPeople;
}
In my dataset, I don't care about people that are in listB but not listA, so I don't need to loop through both lists. I only need to check listA for the element in listB (that may or may not be there) and return a list of people that have been modified (with the elements from listA).
This approach worked fine for reasonably small lists, but now I have two lists with about 160,000 people and this approach takes several minutes. Is there any way to make this method more efficient while still returning what I need it do?
If you can change your lists to be a Dictionary<int, Person> with the person's ID as the key they this would work for you. This will run in O(n) as opposed to your O(n^2).
public static List<Person> FindModifiedPeople(Dictionary<int, Person> dictA, Dictionary<int, Person> dictB)
{
var modifiedPeople = new List<Person>();
foreach (var personA in dictA)
{
Person matchingPerson;
if(dictB.TryGetValue(personA.Key, out matchingPerson))
{
if (!personA.Value.IsEqual(matchingPerson))
{
modifiedPeople.Add(personA.Value);
}
}
}
return modifiedPeople;
}
You could also change the return type from List to another Dictionary as well depending on what you need it for.
EDIT
As #maccettura pointed out in his comment, you really should override the built in equals method. That would make your code look something like this.
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
var otherPerson = (Person)obj;
if (Name != otherPerson.Name)
{
return false;
}
if (Age != otherPerson.Age)
{
return false;
}
return true;
}
This will allow your code to work with any stuff that is expecting to use the default Equals method as opposed to your custom one.
Are you sure that the comparison is the bottleneck? I think that the problem comes form the search you do in this line:
var matchingPerson = listB.FirstOrDefault(e => e.ID == personA.ID);
There, you are doing a search with a logartihmic complexity of O(n), which coupled with the foreach loop gives a total complexity of O(n^2). Instead, you could create a dictionary upfront, which takes some time, but in which lookups are much faster. The dictionary should have the ID as keys, and can be easily created like this BEFORE THE foreach LOOP:
var dictB = listB.ToDictionary(p => p.ID);
After that, your lookup would be much faster, like this:
Person matchingPerson;
if (dictB.TryGetValue(personA.ID, out matchingPerson))
{
if (!personA.IsEqual(matchingPerson))
{
modifiedPeople.Add(personA);
}
}

C# : LINQ query to list all empty properties of a class

I have a class like this :
public class Test
{
public string STR1{ get; set; }
public INT INT1{ get; set; }
public DOUBLE DBL1{ get; set; }
public DATETIME DT1{ get; set; }
}
Normally, before saving the object, i will have to check all the properties inside this Class, and return a warning message if there is any empty/null property. There is easy way to do this by simply check each property like this :
if (string.IsNullOrEmpty(t.STR1))
return "STR1 is empty"
if (t.INT1 == 0)
return "INT1 = 0";
if (t.DBL1 == 0)
return "DBL1 = 0";
if (t.DT1 == DateTime.MinValue)
return "DT1 is empty"
But what if my class has more properties, actually it contains about 42 properties now, and still growing up. So i was thinking for a "cleaner" way to perform this check, and i found this topic which is quiet similar to my issue : Reflection (?) - Check for null or empty for each property/field in a class?
But this solution does not meet my need as i have to list the values that = null/empty string/0/DateTime.MinValue
Believe me, i wanted to post my "tried code" but i can't figure out a sensible LINQ query for this task (i'm a novice in C#)
Any help is greatly appreciated !
Since you need to test objects of different types, you can combine the solution from the linked question with use of dynamic to dispatch to the proper method.
First, define an overloaded method for each type.
private static IsEmpty(string s) { return string.IsNullOrEmpty(s); }
private static IsEmpty(double f) { return f == 0.0; }
private static IsEmpty(int i) { return i == 0; }
private static IsEmpty(DateTime d) { return d == DateTime.MinValue; }
Now you can use these methods in your check:
List<string> emptyProperties = typeof(MyType).GetProperties()
.Select(prop => new { Prop = prop, Val = prop.GetValue(obj, null) } )
.Where(val => IsEmpty((dynamic)val.Val) // <<== The "magic" is here
.Select(val => val.Prop.Name)
.ToList();
The tricky part of the code casts the value to dynamic, and then tells the runtime to find the most appropriate IsEmpty method for it. The downside to this approach is that the compiler has no way of telling whether the method is going to be found or not, so you may get exceptions at runtime for properties of unexpected type.
You can prevent these failures by adding a catch-all method taking object, like this:
private static IsEmpty(object o) { return o == null; }

Convert Nulls to Empty String in an object

What is the easiest way to take an objects and convert any of its values from null to string.empty ?
I was thinking about a routine that I can pass in any object, but I am not sure how to loop through all the values.
When your object exposes it's values via properties you can write something like:
string Value { get { return m_Value ?? string.Empty; } }
Another solution is to use reflection. This code will check properties of type string:
var myObject = new MyObject();
foreach( var propertyInfo in myObject.GetType().GetProperties() )
{
if(propertyInfo.PropertyType == typeof(string))
{
if( propertyInfo.GetValue( myObject, null ) == null )
{
propertyInfo.SetValue( myObject, string.Empty, null );
}
}
}
Using reflection, you could something similar to :
public static class Extensions
{
public static void Awesome<T>(this T myObject) where T : class
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach(var info in properties)
{
// if a string and null, set to String.Empty
if(info.PropertyType == typeof(string) &&
info.GetValue(myObject, null) == null)
{
info.SetValue(myObject, String.Empty, null);
}
}
}
}
Presumably, you have a report or a form somewhere showing "null" all over the place, instead of a nice, pleasant "".
It's best to leave the nulls as they are, and modify your display code wherever appropriate. Thus, a line like this:
label1.Text = someObject.ToString();
should become:
if (someObject == null)
{
label1.Text = ""; // or String.Empty, if you're one of *those* people
}
else
{
label1.Text = someObject.ToString();
}
and you can functionalize it as necessary:
public void DisplayObject(Label label, Object someObject)
{
if (someObject == null)
{
label.Text = ""; // or String.Empty, if you're one of *those* people
}
else
{
label.Text = someObject.ToString();
}
}
You could use reflection. Here's an example with one level of nesting:
class Foo
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo
{
Prop1 = (string)null,
Prop2 = (string)null,
Prop3 = (string)null,
};
var props = typeof(Foo).GetProperties()
.Where(x => x.PropertyType == typeof(string));
foreach (var p in props)
{
p.SetValue(foo, string.Empty, null);
}
}
}
You can do that via reflection without too much trouble, and I am sure that by the time I post this there will be answers that tell you exactly how to do that.
But I personally don't like the reflection option.
I prefer to maintain object invariants for all of the object's members through a variety of means. For string members, the invariant is often that it not be null, and sometimes there are maximum length requirements as well (for storage in a database, for example). Other members have other sorts of invariants.
The first step is to create a method that checks all the invariants that you define for the object.
[Conditional("DEBUG")]
private void CheckObjectInvariant()
{
Debug.Assert(name != null);
Debug.Assert(name.Length <= nameMaxLength);
...
}
Then you call this after any method that manipulates the object in any way. Since it is decorated with the ConditionalAttribute, none of these calls will appear in the release version of the application.
Then you just have to make sure that none of the code allows any violations of these invariants. This means that the string fields need to have either initializers in their declarations or they need to be set in all the constructors for the object.
A special problem, and the one that probably motivated this question, is what to do about automatic properties.
public string Name { get; set; }
Obviously, this can be set to null at any time, and there's nothing you can do about that.
There are two options with regard to automatic properties. First, you can just not use them at all. This avoids the problem entirely. Second, you can just allow any possible string value. That is, any code that uses that property has to expect nulls, 10 mb strings or anything in between.
Even if you go with the reflection option to remove nulls, you still have to know when to call the magic-null-removal method on the object to avoid NullReferenceExceptions, so you haven't really bought anything that way.
+1 to Tanascius's answer. I used this answer but tweaked it a bit.
First I only grab the properties that are strings, so it doesn't loop through all my properties. Secondly, I placed in it my BaseEntity class that all my entities inherit from, which makes it global, so I don't have to put it on all my Entities.
public class BaseEntity
{
public int Id { get; set; }
public BaseEntity()
{
var stringProperties = this.GetType().GetProperties().Where(x => x.PropertyType == typeof(string));
foreach (var property in stringProperties)
{
if (property.GetValue(this, null) == null)
{
property.SetValue(this, string.Empty, null);
}
}
}
}

Categories

Resources