Code structure, a methods should only do one thing - c#

I am having a bit following the "a method should only do one thing"
I have a car text file, and if it contains even one BMW I want to set isValid to true, but while I am going through the text file anyways I thought I would also populate two list high end models(M3,M5 etc) and lower model (335, X3 etc).
I know that method should only do one thing, but it seems so convenient for it to also populate the lists. Here is what I have:
private bool hasBMWegments()
{
foreach (ClassLib.CarSegment carElement in CarSegmentFactory.ContainsCar("BMW"))
{
isValid = true;
if (carElement.Class.IndexOfAny(lowerModels) == 0)
{
lstOlderSegment.Add(carElement.ElementNumber);
}
if (carElementClass.IndexOfAny(upperModels) == 0)
{
lstNewerSegment.Add(carElement.ElementNumber);
}
}
return isValid;
}
Should I just create a method that performs the foreach check again? Or should I create another method inside that method (I would think that would be messy, and wouldn't related to the method name)
edit: sorry working with framework 2.0

I find that code to be a mess compared to this:
private IEnumerable<ClassLib.CarSegment>
GetModels(IEnumerable<ClassLib.CarSegment> segments, string modelID)
{
return segments.Where(x => x.Class.IndexOfAny(modelID) == 0);
}
// ...
var bmwSegments = CarSegmentFactory.ContainsCar("BMW").ToArray();
bool isValid = bmwSegments.Any();
var olderModelSegments = GetModels(bmwSegments, lowerModels);
var newerModelSegments = GetModels(bmwSegments, upperModels);
This code is obviously correct at a glance. The other code makes you look twice at the loop to figure out what's going on.

It looks like all you're doing is setting isValid to true on the first pass through the foreach. So all isValid really means is "is there at least one element?".
In which case you do not need to iterate twice. You can use Any() to do the valid check:
bool IsValid(IEnumerable<CarSegment> elements)
{
return elements.Any();
}
void PopulateSegments(IEnumerable<CarSegment> elements)
{
foreach(var element in elements)
{
//add to lists
}
}

Related

How to convert float to system.Collection.generic.IEnumerable

How to convert float to system.Collection.generic.IEnumerable
The actual problem occurs when I try to iterate through the returned IEnumerable.
Code
private ObservableRangeCollection<ReviewInfo> _rating = new ObservableRangeCollection<ReviewInfo>();
public ObservableRangeCollection<ReviewInfo> Review
{
get { return _rating; }
set { _rating = value; OnPropertyChanged("AvRating"); }
}
public async Task GetReview()
{
var ber_id= berProfile.Id;
ResponseInfo<ReviewInfo> res = await nsManager.Instance.GetReview(ber_id);
Device.BeginInvokeOnMainThread(async () => {
IsBusy = false;
if (res.IsError == true)
{
await _page.Alert(res.Message);
}
else
{
if (res.Data != null && res.Data.Count > 0)
{
var temp = res.Data.Average(x => x.Rating);
Review.AddRange(temp);
}
}
});
}
Review is a collection of GogroomCustomer.Models.ReviewInfo, so you should create ReviewInfo object from temp by constructor or set via Property (ex: reviewInfo), then use Add or AddRange method:
Review.Add(reviewInfo);
or
Review.AddRange(new ReviewInfo[] { reviewInfo });
Your question is quite unclear as you didn´t provide what a ReviewInfo is. However your error is quite clear: you´re trying to add a float to a list of ReviewInfo. Of course this won´t work.
From your code I suppose this class has at least a Rating-property or field. Assuming you have a list of those ReviewInfo-instances you probably want to retrieve that object whose Rating-property is the average of all the elements within your list.
If this is the case your solution is simply this:
var temp = res.Data.Average(x => x.Rating);
Review.Add(res.Data.First(x.Rating == tmp));
However as Average returns a double it is fairly possible that there´s no element with exactly this rating in your list, so it´s better to apply some tolerance. However this goes too far on guessing what you actually want.

EWS comparing ItemIDs shows no match but ItemID.ToString comparison shows a match.

I am using EWS to find items. I expect the result set to be larger than the page size so I have implemented a check to ensure my result set doesn't change while paging. The code is pretty much the same as recommended by Microsoft at the link below.
How to: Perform paged searches by using EWS in Exchange
Here is the relevant code snippet:
if (results.Items.First<Item>().Id != anchorId)
{
Console.Writeline("The collection has changed while paging. " +
"Some results may be missed.");
}
The problem is, the first ItemID and the acnchorID never match even though I am sure the collection is not changing. Further to this, if I convert the IDs to strings and do a string comparison as below, they always match.
string a = results.Items.First<Item>().Id.ToString();
string b = anchorId.ToString();
bool result = a.Equals(b, StringComparison.Ordinal);
Debug.Print("Ordinal comparison: {0}",result ? "equal." : "not equal.");
I have tried running the code on different result sets and with different page sizes and the outcome is always the same: the ItemIds never match but the ID strings always match.
Question
I am reluctant to drop the approach recommended by Microsoft in favor of a string comparison approach especially as I can't explain why the FolderID comparison approach isn't working. But, on the other hand, I can't explain why the string comparison always works. Does anyone have any thoughts on why I might be seeing these strange and conflicting results.
What i sucpect is happening in this line:
if (results.Items.First<Item>().Id != anchorId)
Seeing that the ItemId object, or its parents, do not override the != operator. The object references of the ItemId are being compared. And this should always return true because we create a different object for each ItemId.
But the toString() method is being overriden by this :
public override string ToString()
{
return (this.uniqueId == null) ? string.Empty : this.uniqueId;
}
Which explains why comparing this results in a good comparison of the keys.
The best way to handle this i think is to use the equals method of the ItemId class which has its own implementation:
public override bool Equals(object obj)
{
if (object.ReferenceEquals(this, obj))
{
return true;
}
else
{
ServiceId other = obj as ServiceId;
if (other == null)
{
return false;
}
else if (!(this.IsValid && other.IsValid))
{
return false;
}
else
{
return this.UniqueId.Equals(other.UniqueId);
}
}
}
So conclusion use this for the comparison of the keys:
if (!results.Items.First<Item>().Id.Equals(anchorId))
{
Console.Writeline("The collection has changed while paging. " +
"Some results may be missed.");
}
And if u are interested u can visit the github page for the source code: https://github.com/OfficeDev/ews-managed-api

Unit Testing: Can't figure this out?

I'm doing a unit test in my design class, and the shell of the project was given to us. There is only one method in the unit test where I have to add code. I can't change anything else in the code.
I have tried everything I could think of using what C++ knowledge I have and tried Googling different ways to solve this problem. Every result that came up was either too complex because I don't have a background with C#, or the information for what I was looking for was not given.
Here is the original code:
class Course
{
public Course(string id, string title, int creditHours, string description, string prerequisiteCourse)
{
this.CourseID = id;
this.CourseTitle = title;
this.CreditHours = creditHours;
this.Description = description;
this.PrerequisiteCourse = prerequisiteCourse;
}
public string CourseID;
public string CourseTitle;
public int CreditHours;
public string Description;
public string PrerequisiteCourse;
}
class CourseListTest
{
public static void Main(string[] args)
{
GetCourseByCourseIDTestWhenCourseExists();
GetCourseByCourseIDTestWhenCourseDoesNotExist();
}
public static void GetCourseByCourseIDTestWhenCourseExists()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 400");
if (myCourse.CourseID != "CIS 400")
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseExists(): Returned CourseID Not equal (CIS 400)");
}
public static void GetCourseByCourseIDTestWhenCourseDoesNotExist()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 101");
if (myCourse != null)
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseDoesNotExist(): should have returned null");
}
}
Here is were the problem lies in the next class. We are to enter code into the GetCourseByCourseID method which is where I get stuck.
class CourseList
{
public Course[] CourseArray =
{
new Course ("CIS 400", "OO Analysis & Design", 4, "Important class", "CIS 110") ,
new Course ("CIS 150A" , "VB.NET Programming", 4, "Good Introduction to programming", "CIS 100") ,
new Course ("CIS 150B", "C# Programming with labs", 4, "Follow-up to CIS 100", "CIS 100")
};
public Course GetCourseByCourseID(string id)
{
}
}
Since "CIS 101" is not a course in the CourseList we have to return null. The whole point of the exercise is to get the console to display nothing. That means the code is working properly.
I don't want the answer. I was just wanted an example of how to get this to work. Being that the code was already given to us.
i'll keep this close to c++ syntax.
there are many other ways but...
public Course GetCourseByCourseID(string id)
{
for(int x = 0; x < CourseArray.Length; x++)
{
if(CourseArray[x].CourseID == id) {return CourseArray[x];}
}
return null;
}
your array is static you could just use x < 3
and for a more c# way
using System.Linq;
public Course GetCourseByCourseID(string id)
{
return CourseArray.Where(a => a.CourseID == id).FirstOrDefault();
}
a is each course and First return the first element in the resulting collection. a pit fall with this approach is that if you have more than one Course with the same id you only get the first one.
but then that is likely a design flaw.
it should be noted that if CourseArray were to be multidimensional. then length would not be usable because it return the total number of elements in all dimensions of the array. thus using System.Linq Count() extension method would have to be used.
The simplest way would be to use a foreach loop, checking through all the courses until the ID matches. If no ID matches, the loop will exit and you should return null.
The more 'advanced' way would be to use LINQ, either straight up LINQ or the extension methods to achieve the same result but with less code.
With any language it is best to state a return variable which will start in a failure state. Then do the work of trying to find the non failure state and assign it to the return variable. If one doesn't find a non failure state, no assignment is done and the return value is correct as null.
Example:
public Course GetCourseByCourseID(string id)
{
Course foundCourse = null;
if (CourseArray != null)
{
// Check course array here for the id and if one is found, assign to foundCourse.
}
return foundCourse;
}
So within the if's you can continue to remove any possible failure situations. The one above in the if checks CourseArray for null. If it is null it gracefully exits and doesn't throw an exception about trying to check CourseArray. Keep doing 'sanity' checks where possible and it makes for better programming.

Checking if all values are null inside an initialised object

I have some code that reads data from Excel sheets & put to List.
Now here comes a scenario that user copy some valid data then leaves a lot of rows empty & again then copy valid data. This reads a lot of empty rows. I am using some old code for excel read & that might be used somewhere else so I don't wish to mess up with that.
The problem is I have a lot of object inside List that are initialised but all values are null. So I ended up checking all attribuets in if like:
if (lstConsolidatedData != null)
{
foreach (var lst in lstConsolidatedData)
{
if(lst.a!=null && lst.b!=null && lst.c!=null //& so on....)
{
//some stuff...
}
}
}
I know this is not wither best or maintainable way since excel sheets can be modified & thus whole columns list code need to be changed again & again for a single column added or removed from excel.
Is there any way to check all values inside lst for null in a single statement?
some thing like lst.all !=null
Any idea if not code will also work for me.
Please note lst==null is false
EDIT: using answers from below I am getting this error
EDIT:
o.GetType().GetProperties().Any(c => c.GetValue(o) == null) works for any null but What I actually want to delete rows which contains no data in all columns not for particular one or two column. Issue is not resolved by o.Item1 != null && ... also since name/number of columns changes frequently.
You can use reflection to do this, but beware that it carries performance losses over doing it explicitly.
public bool IsAnyPropertyNull(object o)
{
return o.GetType().GetProperties().Any(c => c.GetValue(o) == null);
}
There is, however, no built-in expression to reduce the o.Item1 != null && o.Item2 != null && ... type syntax.
Also, I'm assuming the values you're talking about are properties. You could also use GetFields or whatever you need if that's more appropriate.
As Mathew Huagen pointed out using reflection to get properties and then checking their values seems to be fine. However, this has a big caveat that is there may be some properties you don't want to be checked. To solve this,you can either put them inside a list (as Tim Schmelter mentioned), or you can decorate desired properties of ConsolidatedData with a custom attribute to distinguish them:
public class ConsolidatedData
{
public int Id { get; set; }
[NotNull]
public object PropertyOne { get; set; }
[NotNull]
public object PropertyTwo { get; set; }
}
public class NotNull : Attribute { }
Then checking against null is safe when you filter out the properties not having NotNull attribute:
ConsolidatedData v = new ConsolidatedData();
bool allNotNull = v.GetType().GetProperties()
.Where(p => null != (Attribute.GetCustomAttribute(p, typeof(NotNull)) as NotNull))
.All(p=>p.GetValue(v) !=null );
Here property Id is not get checked.
You could write an extension method for your ConsolidatedData like this;
public static bool IsAnyPropNull(this ConsolidatedData cdata)
{
return cdata.GetType().GetProperties().Any(p => p.GetValue(this) == null);
}
And you could then filter your list with a one-liner;
var filteredList = lstConsolidatedData.Where(cd => !cd.IsAnyPropNull()).ToList();
This will return a list of all object without nulls. If you want the nulls, remove the !, ofcourse.
Edit;
Wow, my answer is almost the same as Matthew Haugen's... both should work fine, even though the implementation is slightly different.
I ended up digging down into old code & before turning dataset into List I deleted empty rows using code:
//Deleting empty records from Datset
foreach (DataTable source in result.Tables)
{
for (int i = 0; i < source.Rows.Count; i++)
{
DataRow currentRow = source.Rows[i];
bool isEmpty = false;
foreach (var colValue in currentRow.ItemArray)
{
if (!string.IsNullOrEmpty(colValue.ToString()))
{
isEmpty = false;
break;
}
else
isEmpty = true;
}
if (isEmpty)
source.Rows[i].Delete();
}
}
result.AcceptChanges();
Don't forget .AcceptChanges() since it actually save the changes done to dataset without which no records are removed.

Passing properties as parameters

I want to create a generalized helper method for LoadFromXML loading and validation. If the XML I'm loading from is incomplete, I do want it to fail completely without throwing an exception. Currently, my code looks like this (more or less)
public override bool Load(XElement source)
{
return new List<Func<XElement, bool>>
{
i => this.LoadHelper(i.Element(User.XML_Username), ref this._username, User.Failure_Username),
i => this.LoadHelper(i.Element(User.XML_Password), ref this._password, User.Failure_Password)
//there are many more invokations of LoadHelper to justify this architecture
}
.AsParallel()
.All(i => i.Invoke(source));
}
private bool LoadHelper(XElement k, ref string index, string failure)
{
if (k != null && k.Value != failure)
{
index = k.Value;
return true;
}
return false;
}
this._username is a private member variable that is used by the property this.Username. This is the current solution I have for this problem, but I'm facing one major issue: Since I cannot pass the property itself to the LoadHelper and Action<string> doesn't match the property :(, I'm circumventing the property setter logic right now.
For your own musings, before the LoadHelper abstraction, each of my List<Func<XElement, bool>>'s entries looked like this...
i => ((Func<XElement, bool>)(k => { if (k == null || k.Value == User.Failure_Username) return false;
{ this.Username = k.Value; return true; } })).Invoke(i.Element(User.XML_Username)),
Question: Does anyone know any way to do this without circumventing the property's setter logic?
Action doesn't match the property
If I read that right, you tried replacing the "ref string index", with "Action<string>" and then tried passing the Protperty. Close but not quite. How 'bout?
private bool LoadHelper(XElement k, Action<string> setter, string failure)
{
if (k != null && k.Value != failure)
{
setter(k.Value);
return true;
}
return false;
}
then
i => this.LoadHelper(i.Element(User.XML_Username), s=>{this.Username = s},
User.Failure_Username),
I've sometimes wondered how much it would bloat things for .Net to support an iProperty(of T) interface with two members, Get and Set, and automatically wrap fields and properties so that an iProperty(of T) parameter could be passed a field or property.
Using anonymous methods, one could create such a thing not too totally horribly by creating an xProperty class whose constructor took the methods necessary to get and set a property. One could define instances of the class for any properties that one wanted other classes to be able to manipulate directly. Things would be much nicer, though, if there were a standard interface. Unfortunately, I'm unaware of one existing.

Categories

Resources