Avoiding twice coding, One in if Condition and One in Assignment - C# - c#

Here is my sample code:
if (_Timing != target.Split(':')[0] + ": ")
_Timing = target.Split(':')[0] + ": ";
I check if _Timing is not equal to target.Split(':')[0] + ": " then I will assing it to _Timing. I execute this target.Split(':')[0] + ": " two times. I need to avoid it.
another example is this:
if (db.Students.FirstOrDefault(x => x.Name == "Joe") != null)
var a = db.Students.FirstOrDefault(x => x.Name == "Joe");
here again, I execute db.Students.FirstOrDefault(x => x.Name == "Joe") two times. These samples are just some examples. I need to avoid twice coding like these.
I can do this due to answers received:
var splitted= target.Split(':')[0] + ": ";
if (_Timing != splitted)
_Timing = splitted;
But I don't want to do something like this, because splitted will remain in memory. I'm looking for a way to not saving this temporary data into memory.
Is there any advice?

You can hold the reusable statement in a variable and reuse wherever needed further down in your flow control:
var splitted= target.Split(':')[0] + ": ";
if (_Timing != splitted)
_Timing = splitted;
the same goes for the linq queries :
var student = db.Students.FirstOrDefault(x => x.Name == "Joe");
if (student != null)
{
// do something here with student
}
if you want to avoid writing the linq query then you can introduce methods too:
public Student GetStudentByName(string name)
{
return db.Students.FirstOrDefault(x => x.Name == "Joe");
}
and reuse it:
var student = GetStudentByName("Joe");
if (student != null)
{
// do something here with student
}

According to your requirement you say that:
I can do this due to answers received:
var splitted= target.Split(':')[0] + ": ";
if (_Timing != splitted)
_Timing = splitted;
But I don't want to do something like this, because splitted will remain in memory. I'm looking for a way to not saving this temporary data into memory.
Is there any advice?
Yes There is one way to explicity remove variable from a memory.
You can try this to achieve that same thing and the variable splitted no longer remains in memory:
var splitted= target.Split(':')[0] + ": ";
if (_Timing != splitted)
{
_Timing = splitted;
splitted = null;
GC.Collect(); // It this stage the 'splitted' is not longer remain in the memory.
}

Remove the if block.
_Timing = target.Split(':')[0] + ": ";
Move assignment out of the if block
var student = db.Students.FirstOrDefault(x => x.Name == "Joe");
if (student != null)
{
//
}

Related

Saving objects with FindObjectsOfTypeAll()

I have a save-Method to save informations about every block with one of five specific tags, like position, health, rotation etc.
I first want to get all objects (even inactive ones), so i use the FindObjectsOfTypeAll()-Method.
Then i go with a foreach loop through all of the objects that have been found, and check if they have the right tag and if they do, i save them.
This is the code i use:
GameObject[] allObjects = Resources.FindObjectsOfTypeAll(typeof (GameObject)) as GameObject[];
using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
Debug.Log(allObjects.Length);
foreach (GameObject block in allObjects)
{
bool isActive = block.activeSelf;
block.SetActive(true);
if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor")
{
// SAVE
write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z);
}
block.SetActive(isActive);
}
write.Close();
}
I debugged this and the line if (block.tag == "WoodBlock" || ...) works fine.
The problem is the next line:
write.WriteLine(...);
here i get a nullReferenceException, where it tells me:
NullReferenceException: Object reference not set to an instance of an
object
And i can't figure out why?!
The issue is very probably that
block.GetComponent<BlockControl>()
returns null for one of your found GameObjects since it simply does not have that component.
Instead you could use
Resources.FindObjectsOfTypeAll<BlockCo troll>();
to be sure you only have all the components of type BlockControl in a separate list.
Than you can use a List to easier filter the objects for the tag instead of those || conditions
var searchedTags = new List<string>()
{
"WoodBlock",
"WoodSteps",
"WoodRamp",
"GlasBlock",
"WoodDoor"
};
if (searchedTags.Contains(block.gameObject.tag))
{
....
}
or even esier use Linq to only get the objects you are interested in:
var objectsOfInterest = allObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();
I would also only use the StreamWriter for actually writing and do nothing else within that using block.
And note that if you are using a StreamWriter inside of a using block you don't have to use write.Close() since it is disposed automatically after the using block finishes.
So in complete I would use something like
var searchedTags = new List<string>()
{
"WoodBlock",
"WoodSteps",
"WoodRamp",
"GlasBlock",
"WoodDoor"
};
// This list is used to get all GameObject
// keep track which where active and activate all
var allObjects = Resources.FindObjectsOfTypeAll<GameObject>();
// Here we get all BlockController components
var allBlockObjects = Resources.FindObjectsOfTypeAll<BlockController>();
// finally we only get BlockControllers with the tags we want
var objectsOfInterest = allBlockObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();
Debug.Log("objects total: " + allObjects.Length);
Debug.Log("block objects: " + allBlockObjects.Length);
Debug.Log("objects of interest: " + objectsOfInterest.Length);
// Step 1 keep track which GameObjects where active and activate all
var objectWasNotActive = new List<GameObject>();
foreach (var obj in allObjects)
{
if(!obj.activeSelf)
{
// keep track which objects where not active
objectWasNotActive.Add(obj);
}
// Set all to true
obj.SetActive(true);
}
// Step 2 save your BlockControllers with searched tags
using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
foreach (var block in objectsOfInterest)
{
// Here you already have components of type BlockController
// so you don't need to get them
// But GetHealth might also return null so maybe you want to check that too
// It is up to you whether you want to skip or fill it with default values in such case
var health = block.GetHealth();
if(health == null)
{
//option 1 skip
continue;
// OR option 2 default e.g.
// Assuming it is Vector2
health = Vector2.zero;
}
// SAVE
write.WriteLine(
block.gameObject.tag + ","
+ block.transform.position.x + ","
+ block.transform.position.y + ","
+ block.transform.position.z + ","
+ health.x + ","
+ health.y + ","
+ block.transform.rotation.x + ","
+ block.transform.rotation.y + ","
+ block.transform.rotation.z
);
}
}
// Step 3 disable those GameObjects again that where not active before
foreach(var obj in objectWasNotActive)
{
obj.SetActive(false);
}
Now it's really hard to debug this without seeing the code, but try checking this first.
Check if write is being properly initialized without errors, sometimes it fails silently.
Are you sure that all of your objects with those tags have the component BlockControl on them ?
try updating your code to this just to check where exactly is it failing
if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor")
{
Debug.Log(block.name);
Debug.Log(block.GetComponent<BlockControl>());
Debug.Log(block.GetComponent<BlockControl>().GetHealth());
// SAVE
write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z);
}
This way you can find out which block is causing the issue and if the problem is with the component or the GetHealth() function.

How to get same functionality as ISNULL in LINQ query

I have been trying to find a solution for this since part few hours and I feel like my brain is about to help. I have the below LINQ query.
DropDownListItem item = (
from c in context.Practitioners
where c.PractitionerID == id
select new DropDownListItem
{
Id = c.PractitionerID,
DisplayValue = c.FirstName + " " + c.MiddleName + " " + c.LastName,
IsActive = c.IsActive,
DisplayOrder = c.PractitionerID,
CreatedById = new Guid("COFFEEOO-LOVE-LIFE-LOVE-C0FFEEC0FFEE"),
CreatedDate = c.CreatedDate,
}).FirstOrDefault() ?? new DropDownListItem();
response.Data = item;
There are instaces when c.MiddleName could be null. How Can I handle it in this query so that if c.MiddleName is null I can just assign a blank "" string to it ?
Here's what I tried already which did not work out.
- Created extension to check IsNullOrEmpty. I found out this does not work on LINQ queries.
- tried converting c.Middle to string by doing something like c.MiddleName.ToString() which did not work for LINQ query either.
Please give me more more direction as to which I should move toward. Thanks!
You can check for nulls and empty strings instead of using any methods that LINQ to Entities does not understand (Trim will be translated to SQL):
DisplayValue = c.FirstName + " " + ((c.MiddleName == null || c.MiddleName.Trim() == string.Empty) ? string.Empty : (c.MiddleName + " ")) + c.LastName,
I'm a bit confused about your question. You are making a string, so even if c.MiddleName is null it should be interpreted as an empty string.
You can also try this:
DisplayValue = (c.MiddleName != null) ?
c.FirstName + " " + c.MiddleName + " " + c.LastName :
c.FirstName + " " + c.LastName,
But pretty much all other answers are very similar.
As a note, you are missing brackets behind select new DropDownListItem, so that might be problem.
I'll assume what you mean by c.MiddleName is empty is that c.MiddleName is null (because if it's an empty string you question makes no sense :p).
If it is indeed the case try writing c.MiddleName ?? ""
This means that if the left part of ?? is null the use the right part of the expression
See https://msdn.microsoft.com/en-us/library/ms173224.aspx for more documentation
And you would have to change your code in this fashion :
DropDownListItem item = (
from c in context.Practitioners
where c.PractitionerID == id
select new DropDownListItem
{
Id = c.PractitionerID,
DisplayValue = (c.FirstName ?? "") + " " + (c.MiddleName ?? "") + " " + (c.LastName ?? ""),
IsActive = c.IsActive,
DisplayOrder = c.PractitionerID,
CreatedById = new Guid("COFFEEOO-LOVE-LIFE-LOVE-C0FFEEC0FFEE"),
CreatedDate = c.CreatedDate,
}).FirstOrDefault() ?? new DropDownListItem();
response.Data = item;
To be noted that the ?? operator have one of the lowest priorities in C#.
Check the operators priority in C# here https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
try this
DisplayValue = (c.FirstName?? string.Empty) + " " + (c.MiddleName ?? string.Empty) + " " + (c.LastName?? string.Empty)

Make string checker more efficient

I am using the following code to check if a string is contained within another string -
foreach (string testrecord in testlist)
{
foreach (string realrecord in reallist)
{
if ((Regex.Replace(testrecord , "[^0-9a-zA-Z]+", "")
.Contains((
Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "")))
&&
((Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "") != "")
&&
((Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "").Length >= 4)))))
{
matchTextBox.AppendText("Match: " + testrecord + " & " + realrecord + Environment.NewLine);
}
}
}
However the runtime for this to finish is taking quite a while. Since I added the special character regex removal the runtime is taking a lot longer however the regex is definitely required.
Is there a more efficient way of applying this regex? I tried to add it to the foreach string variables however you cannot alter them as they are in a foreach loop.
Optimized version:
// Do not put text into matchTextBox direct:
// it makes the control re-painting each time you change the text
// Instead, collect all the text into StringBuffer
StringBuilder Sb = new StringBuilder();
// Pull out as much as you can from the inner loop,
// that's why I've changed the loops' order:
// first loop on reallist, then on testlist
foreach (string realrecord in reallist) {
// Cache Regex.Replace result
String realCleaned = Regex.Replace(realrecord, "[^0-9a-zA-Z]+", "");
// Test as early as possible
if (realCleaned.Length < 4)
continue;
// You don't need to test realCleaned != "";: realCleaned.Length < 4 is enough
foreach (string testrecord in testlist) {
// Cache Regex.Replace result: it's a little bit overshoot here, but if some
// more tests are added it'll be helpful
String testCleaned = Regex.Replace(testrecord, "[^0-9a-zA-Z]+", "");
if (testCleaned.Contains(realCleaned))
Sb.AppendLine("Match: " + testrecord + " & " + realrecord);
}
}
// At last matchTextBox.Text change
matchTextBox.AppendText(Sb.ToString());
This should be a bit quicker (one regex operation per testrecord):
var strippedRealList = reallist.Select(s => Regex.Replace(s, "[^0-9a-zA-Z]+", ""))
.Where(s => s.Length >= 4)
.ToArray();
foreach (string realrecord in reallist)
{
strippedRealList.Where(s => realrecord.Contains(s))
.ToList()
.ForEach(s =>
matchTextBox.AppendText("Match: "
+ s
+ " & "
+ realrecord
+ Environment.NewLine));
}
I wonder that you are using Regex to achieve your purpose ignoring the fact that you can also achieve this by only using .Contains() method such that your code should be simple and faster then before
foreach (string testrecord in testlist)
{
foreach (string realrecord in reallist)
{
if(testrecord.Contains(realrecord))
{
matchTextBox.AppendText("Match: " + testrecord + " & " + realrecord + Environment.NewLine);
}
}
}

Linq to sql querying multiple columns - query help

I have a text field on my screen where users can search for a few things from one input field:
Address
Postcode
Client name
ID
What is the best way to write a query that will query these columns?
How should I take the input in, should I split string on space? or comma?
User input = 67 pottors lane 99
where "67 pottors lane" is address
"99" is/could be ID
What I have so far:
//q = querystring
//filteredlist = extension method for the table that I am querying
//clientlist = list of clients I have passed in as a param
//Here is my query for
if (!string.IsNullOrEmpty(q))
{
var result = q.Trim();
filteredlist = filteredlist
.Where(x => x.ID.Contains(q) || x.SubjectPropertyAddress1.Contains(q)
|| x.SubjectPropertyPostCode.Contains(q)
|| clientlist.Any(y=> x.ClientID == y.ClientID && (y.ID.Contains(q) || y.Name.Contains(q)) ));
}
NOTE: I will make use of indexing using sql.
Perhaps an idea: make an extra column in your database with all the columns you want to search for as one big concattenated string. Then do a free text search of your input string versus that field in the DB.
Since L2SQL does not support free text search, you need to do it in stored procedure in that case or do like here (http://stackoverflow.com/questions/67706/linqtosql-and-full-text-search-can-it-be-done)
Ouch - is there no way for you to split the input into separate fields for ID, Address, Postcode and Name?
If so, you can keep appending Where clauses, like
var query = filteredList;
if (!String.IsNullOrEmpty(id))
{
query = query.Where(c => c.ID.Contains(id))
}
if (!String.IsNullOrEmpty(name))
{
query = query.Where(c => c.Name.Contains(name))
}
.. same for Name, address etc
Otherwise, your query resembles more of a search engine query than a RDBMS query.
I have done a very similar thing in the past. I split the search string on the space character and restricted it to a maximum of 6 search "words", so that the linq is still manageable.
I came up with something like the following:
string[] words = q.ToLower().Split(' ');
string[] wordsFixed = new string[] {"", "", "", "", "", "" };
for(int i = 0; i < 6 && i < words.Length; i++)
wordsFixed[i] = words[i];
var data = from item in list
where (item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[0]) &&
(item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[1]) &&
(item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[2]) &&
(item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[3]) &&
(item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[4]) &&
(item.ID + item.Name + item.Address1 + item.Address2 + item.PostCode).ToLower().Contains(wordsFixed[5])
select item;

String list remove

I have this code:
List<string> lineList = new List<string>();
foreach (var line in theFinalList)
{
if (line.PartDescription != "")
lineList.Add(line.PartDescription + " " + line.PartNumber + "\n");
else
lineList.Add("N/A " + line.PartNumber + "\n");
//
//This is what I am trying to fix:
if (lineList.Contains("FID") || lineList.Contains("EXCLUDE"))
// REMOVE THE item in the lineList
}
I am trying to go through theFinalList in a foreach loop and add each line to a new list called lineList.
Once added, I want to remove any entries from that list that contain the text "FID" or "EXCLUDE".
I am having trouble removing the entry, can someone help me?
why add them when you want to remove them right after:
lineList = theFinalList.Select( line =>
{
if (line.PartDescription != "")
return line.PartDescription + " " + line.PartNumber + "\n";
else
return "N/A " + line.PartNumber + "\n";
})
.Where(x => !(x.Contains("FID") || x.Contains("EXCLUDE")))
.ToList();
The following code sample iterates through the lineList and removes lines that contain FID or EXCLUDE.
for(int i = lineList.Count - 1; i >= 0; i--)
{
if (lineList[i].Contains("FID") || lineList[i].Contains("EXCLUDE"))
lineList.RemoveAt(i);
}
It is important to traverse a list in reverse order when deleting items.
You can't remove the items in your theFinalList list while you are iterating over theFinalList in a foreach loop. In this case, you may get System.InvalidOperationException with the message “Collection was modified; enumeration operation may not execute.”
you have to do something like this:
List<string> removals = new List<string>();
foreach (string s in theFinalList)
{
//do stuff with (s);
removals.Add(s);
}
foreach (string s in removals)
{
theFinalList.Remove(s);
}
try
foreach (var line in theFinalList)
{
string T = "";
if (line.PartDescription != "")
T = line.PartDescription + " " + line.PartNumber + "\n";
else
T = "N/A " + line.PartNumber + "\n";
if (!(T.Contains("FID") || T.Contains("EXCLUDE"))
lineList.Add (T);
}
I think its more logical approach
Regex exclude = new Regex("FID|EXCLUDE");
foreach (var line in theFinalList.Where(
ln => !exclude.Match(ln.PartDescription).Success &&
!exclude.Match(ln.PartNumber ).Success))){
string partDescription = "N/A";
if(!string.IsNullOrWhiteSpace(line.PartDescription)){
partDescription = line.PartDescription;
}
lineList.Add(partDescription + " " + line.PartNumber + "\n");
}
edit regex for your needs (ignore case maybe or multiline, probably compiled too) and feel free to replace "\n" with Environment.NewLine
Try this:
var excludingTexts = new [] { "FID", "EXCLUDE" }
lineList = lineList.Where(y => !excludingTexts.Any(x => line.PartDescription.Contains(x) || line.PartNumber.Contains(x))).ToList();
Or you can rewrite it as:
var excludingTexts = new [] { "FID", "EXCLUDE" }
List<string> lineList = (from line in theFinalList
where !excludingTexts.Any(x => line.PartDescription.Contains(x) || line.PartNumber.Contains(x))
select line.PartDescription != "" ?
line.PartDescription + " " + line.PartNumber + "\n" :
"N/A " + line.PartNumber + "\n"
).ToList();

Categories

Resources