C#: What technic is that code? - c#

I would like to know:
What technic is that code?
Can you rewrite that code to make it more readable, because I do
not completely understand its meaning.
Paragraph para = CaretPosition.Paragraph;
var matchedRun = para.Inlines.FirstOrDefault(inline =>
{
Run run = inline as Run;
return (run != null && run.Text.EndsWith(inputText));
}) as Run;
if (matchedRun != null)
{
}

I'd say a more readable version would be:
var matchedRun = para.Inlines
.OfType<Run>()
.FirstOrDefault(r => r.Text.EndsWith(intputText));
OfType filters the input sequence on the given type (Run) and FirstOrDefault finds the first Run instance whose Text property ends with the given input (or null if none was found).

It's Linq. Do you know the "var" keyword? It's a type that the compiler knows but the programmer doesn't want to write.
The re-written code without using Linq is
Paragraph para = CaretPosition.Paragraph;
Run matchedRun = null;
foreach (var inl in para.Inlines)
{
Run run = inl as Run;
if( (run != null) && run.Text.EndsWith(inputText))
{
matchedRun = run;
break;
}
}
if (matchedRun != null)
{
}
Note that I converted "inline" to "inl". It's not a keyword in C# but Stackoverflow makes it look like one.
Also note that it's even LESS readable once you get accustomed to Linq!

This code appears to be related to the RichTextBox class in the .NET Framework.
The CaretPosition.Paragraph.Inlines is a collection of "Inlines" that make up the body of the paragraph.
The code is basically looking for any Inlines that are of type Run, and setting the value of matchedRun to that first instance if there are any. The FirstOrDefault method is simply a convenient way to look inside a collection of objects and retrieve the first element or a default value if the collection is empty.
As far as readability, if you are familiar with LINQ syntax, it isn't too bad to wade through that code, though I do personally find the example code provided by Lee to be a bit more readable - mostly because of the use of another LINQ expression: OfType

it's called "THE MIGHTY LINQ TECHNIQUE" :)
Jokes apart
it is Linq method to get the First element from the collection or return default value.
var matchedRun = para.Inlines.FirstOrDefault(inline =>{ Run run = inline as Run; return (run != null && run.Text.EndsWith(inputText));}) as Run;
=> is called the Lambda techique for shorthand delagate decalaration
so you can read it as
Find 1st object from the para.Inlines collection where that object EndsWith some user suplied value or retrun default value if no match found
if you don't want to use this technique which actually reduces lot of code so you can try below equibvalent code
Paragraph para = CaretPosition.Paragraph;
var matchedRun = null;
foreach (var inl in para.Inlines)
{ Run run = inl as Run;
if ((run != null) && run.Text.EndsWith(inputText))
{ matchedRun = run; break; }
}
Now you can decide which is better to write

Related

Declare and assign a variable in if statement condition, reuse in statement body

I can't really phrase the question's title. Anyway, say I have a statement like:
if(myObject.SomeMethod() != null)
{
DoSomethingWith(myObject.SomeMethod());
}
I'd like to avoid a double call to SomeMethod(). Ideally, something à la pattern matching like:
if(myObject.SomeMethod() result != null)
{
DoSomethingWith(result);
}
Is there something in the language that can help me with this? At the moment, my choice is to go with:
var result = myObject.SomeMethod();
if(result != null)
{
DoSomethingWith(result);
}
I know there's nothing wrong in the method above, it's very canonical. Simply put, a lot of syntactic sugar has been added to the language lately, allowing us to condense our code a lot: I'm asking because I don't know if there's something preventing if(myObject.SomeMethod() result != null) to work.
Well, i'd suggest to use a variable as you did in your third code. However...
You can use pattern matching if you don't want to use a variable:
if(myObject.SomeMethod() is var result && result != null)
{
DoSomethingWith(result);
}
But note that this doesn't prevent access to the variable result. You can even access it after the if. If you want that you need a new scope: { if... }.

Null-coalescing operator in a foreach declaration using C#7

I was looking at this code example in C# 7.0 and I was not sure about what was going on under the hood and the performance of this loop.
foreach (var c in text ?? throw new ArgumentNullException(nameof(text)))
{
...
}
My questions:
Does the conditional statement get hit once or multiple times (on
each iteration)?
The new syntax looks different, what are the benefits to doing it this way?
In terms of "how foreach works", conditional statement will only be calculated once.
You may want to read more about how foreach loops work in these questions:
How do foreach loops work in C#?
Does foreach evaluate the array at every iteration?
Thanks to Svek for explaining that it is a new C# 7.0 feature, which will be released after Visual Studio 2017 RC:
http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/
I think that "what are benefits" is a sort of opinion-based question.
In my opinion, it brings nothing good and is just ugly in terms or code readability.
I would recommend using a widely-used common good practice:
if (text == null) // or string.IsNullOrEmpty for strings
throw new ArgumentNullException(nameof(text));
foreach (var c in text)
{
// ...
}
Probably, we will see null-coalescing + throw exception usage in a couple years and it will become a new standard :)
You should understand foreach inner code for understanding this C# feature. A right part of expression in foreach statement must implement IEnumerable(<T>) interface, and whole loop is, internally, a simple while, something like this:
// here can be NullReferenceException
var en = text.GetEnumerator();
while(en.MoveNext())
{
var c = en.Current;
{
...
}
}
As you can see, there is a point in this code the NRE can occur, so you need to check the enumerable before entire loop or Enumerable extensions class, like this:
if (text.IsNullOrWhitespace())
{
throw new ArgumentNullException(nameof(text));
}
// while loop here or text.SomeLinqCodeHere()
There are some lines of code here which aren't really unnecessary, adding some entropy without real value. In case of simple foreach it really opinion-based decision about code standards, but the real purpose of this feature is chaining it with other new things in C#7, like ?. operator, like this:
int? length = customers?.Length ?? throw new ...;
Customer first = customers?[0] ?? throw new ...;
int? count = customers?[0]?.Orders?.Count() ?? throw new ...;
In such cases throwing the exception is similar to comment at the end of the line of code:
int? length = customers?.Length; // should not be null
Customer first = customers?[0]; // should not be null
int? count = customers?[0]?.Orders?.Count(); // should not be null
but it adds some strict contract-like rules for your code.
As for the performance for foreach loop with such expressions, as already said, it doesn't suffer as getting the enumerator occurs only once, and before the real loop.

Can Find() be called multipe times on a MongoCollection?

I am trying to update a property on each object within an array of objects with the value of a property on another object (MyObject). I am unclear if calling:
my_objects_collection = m_database.GetCollection(MY_OBJECTS_COLLECTION_NAME);
has any performance implications, so I tried calling it only once and executing a new Find command against it (with a modified filter for each iteration) within a For... Loop, see below:
MyObject my_object = null;
IMongoCollection<MyObject> my_objects_collection = null;
if (objects != null)
{
my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);
for (int i = 0; i < objects.Count; i++)
{
Expression<Func<MyObject, bool>> filter = x => (x.ID == objects[i].ID) && (x.LanguageCode == language_code);
my_object = await my_objects_collection.Find(filter).FirstOrDefaultAsync();
if (my_object != null)
{ objects[i].DisplayName = my_object.Name; }
}
}
However, the code above throws the following exception:
Value cannot be null.
Parameter name: collection
at MongoDB.Driver.Core.Misc.Ensure.IsNotNull[T](T value, String paramName)
at MongoDB.Driver.IMongoCollectionExtensions.Find[TDocument](IMongoCollection1 collection, Expression1 filter, FindOptions options)
If I move the my_objects_collection assignment inside the for loop, so that it is called for each iteration, the code works without throwing any exceptions.
Therefore my question is, what happens to the MongoCollection reference (my_objects_collection) after the Find (or any other operation) is executed against it?
I would really appreciated if anyone could provide some insight into this. I could move on since my application is working, but I really want to know why it throws an exception indicating that the collection is null for my own understanding.
Thank you in advance,
Andrew
Regardless of your exception, you do not need to perform a find for each individual record you retrieve, you could achieve this using the $in operator.
You could then loop the resultset and perform your update on each document. This is far more efficient as you are performing a single operation against the database to return your records, and then one for each update. Instead of one for each retrieval and one for each update.
See
Builders<MyObject>.Filter.In
Also if you want to match elements in an embedded array you could use
Builders<MyObject>.Filter.ElemMatch
A quick (untested) example
if (objects != null)
{
var my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);
var filterBuilder = Builders<MyObject>.Filter;
var inFilter = filterBuilder.In(x => x.ID, objects.Select(x => x.ID));
var andFilter = filterBuilder.And(
inFilter,
filterBuilder.Eq(x => x.LanguageCode, language_code)
);
var results = await my_objects_collection.Find(andFilter).ToListAsync();
foreach(var result in results)
{
//result is going to the a database object returns which matched your filter
}
}

Iterating through two Lists and checking the item value of the first list to the item values of the second list with a lambda expression

So in the program I'm trying to run I receive two lists, one with objects that contain an id in string format (looks something like "bb_b1203322") and one list with the id's(which in this place is only named "b1203322" for reasons unknown) and a description of the actually id's meaning.
var forms = await _tRepository.GetAllFormsAsync(lastUpdate);
var formDefinitions = await _deRepository.GetAllFormDefintionsAsync();
foreach (var form in forms)
{
foreach (var def in formDefinitions)
{
if (form.SetupFormName.Contains(def.BLKID))
form.SetupFormName = def.DESCR;
}
}
return forms;
Now this piece of code does exactly what I want it to, but I'd rather have it as a lambda expression because ... reasons :)
Now I've tried several different things but with my current knowledge of lambda expressions I can't get it to work.
Try this code. Note that you can use it if formDefinitions with suitable DESCR always exists.
forms.ForEach(f => f.SetupFormName = formDefinitions.FirstOrDefault(fd =>
f.SetupFormName.Contains(fd.DESCR)).DESCR);
This code uses a bit of LINQ to find the definition:
foreach(var form in forms)
{
var def = formDefinitions.FirstOrDefault(x => form.SetupFormName.Contains(x.DESCR));
if(def != null)
form.SetupFormName = def.DESCR
}
As you can see, it's not really saving all that much code.
Please note:
As Jon correctly comments, the behavior of this code is a bit different from your original one. This code uses the first occurrence if there are multiple and your code uses the last occurrence.
If this is actually a use case for your code, replace FirstOrDefault with LastOrDefault.
Extending the code above, you can do something like this:
foreach(var tuple in forms.Select(x => new { Form = x,
Definition =
formDefinitions.FirstOrDefault(y =>
x.SetupFormName.Contains(y.DESCR)) })
.Where(x => x.Definition != null))
{
tuple.Form.SetupFormName = tuple.Definition.DESCR;
}
But as you can see, this gets messy real quick.

Performance tuning for linq/lambda expression

I have some line of code as below.
string result = listDetails
.Where(filename => filename.Contains(fullname)).FirstOrDefault().Split('\\')
.Where(name => name.Contains(nameGivenToSearch)).FirstOrDefault();
if (result.Contains("sd"))
// Do something
While running a tool for checking the performance it shows the performance warning in above statement.
I want to make this more performance feasible. I have heard that nested lambda expression is slower in executing.
Please suggest something to counter this or any link that will be helpful to solve the problem.
Try caching the data searched (or all of it, before your app starts) into the Dictionary<,>.
I would rewrite it as:
string result = listDetails.FirstOrDefault(filename => filename.Contains(fullname));
if (result != null)
result = result.Split('\\').FirstOrDefault(name => name.Contains(namegiventosearch));
if (result != null && result.Contains("sd"))
{
//do task
}
I don't think there is much room for performance improvement.
If my assumption is correct that the list contains paths to files I think the main problem is that you split the path to get the filename. Use functions Path.GetDirectoryName and Path.GetFileName instead. Searching a list of max 1000 string entries should not be to processor heavy
if (listDetails.Where(x => { if(Path.GetDirectoryName(x).Contains(fullname))
{
var file = Path.GetFileName(x);
return file.Contains(namegiventosearch) && file.Contains("sd");
}
else
{
return false;
}
}).FirstOrDefault() != null)
{
// do Task
}
enter code here

Categories