C-Sharp 11 Tips and Tricks


Linq:
- Did you know you could compair two sequences by using sequence operations like below:
- Should be same number element.
 

var wordA = new string[]{kdkd,kdkdk ,kdkd};
var wordB = new string[]{kskks,kdkkd}
bool match = wordA.SequenceEqual(wordB);

- Use Zip to multiply tow array element by element and sum the results

int[] a = {1,2,3,4}
int[] b = {4,5,6,7}
int  sumK = a.Zip(b,(a,b) => a*b).Sum()

- Selecting from multiple input sequences. Selects where first element is less than the other one.

int[] num1 = {3,4,5,6,6}
int[] num2 ={5,6,7,8,9}

var paris = from a in num1
                  from b in num2
                   where a < b
                   select (a,b)






References: Ideas borrowed from link below:
https://github.com/dotnet/try-samples

 


[NB]: Did you know you could write a Switch Statement like this?

var myState = (state,action) switch{
(state.stopped,action.stopped) => state.Froze,
}



How to properly call an Async Function from a Sync Function.
1. Do not use or append .Result to the Async Function you are calling, this hides the Exception into an Aggregate function,
    instead use .GetAwaiter().Result the Exception is handled correctly.

What Not To Do When Developing in C-sharp MVC Application

1. Linq Ordering by multiple Properties
 

public async Task<IEnumerable<MyPoco>> GetAll() => await _context.MyPoco.OrderBy(p => p.Name)//None deterministic Key
                                                                                                                               .ThenBy(p => p.Id)//Key

1.a. Do not mix Async and Sync function calls in one function, this produces a weird behavior that is really hard to debug.

   - The Synchronous function calls might block the Main Thread when there is no data on the Que, while using the Async Await directives this scales better as the UI Thread or Main Thread is not blocked when reading IO data. The throughput is also maximized by using Async Await as other workers are able to pop items off the Que.

[Tip] Instead of creating New Arrays or Lists, just create one List, and then if you need another temp list for sorting purposes just clone/deep copy the existing list into a new one. If using an Array do, Array.Copy() function this will create an array of references to the original Array and will save you allocating objects on the Heap Memory. 

2. Do not retrieve a lot of data more than you need, always choose the columns that are needed.
3. Do not convert all objects loaded into the application to ".ToList", this creates another buffer in the application, remember EF Core creates an internal buffer so when you convert objects to .ToList all the time you need some sort of a list to enumerate then you are creating or buffering data again, this has a performance disadvantage. 

4. Be aware of the Hardware your application is running on, e.g. Memory, IO, Number of Cores, Network Cards, and always benchmark performance to find the bottlenecks and don't assume something before proving the hypothesis.

[NB] Always or mostly use AsEnumerable that is derived from IEnumerable, this will choose the Collection that is suitable for the current scenario as Enumerables are a collection of different Non-Generic Collections like List, Dictionary, HashSet, and Array.
Read here

 


 

6/17/21 [In lieu of Finding ways to reduce object allocation]

1. I found out that you could call the database right on top of the foreach loop, this is called "Streaming" in EF Core, it is another method of retrieving data in a non Synchronous Way, the data retrieved is buffered and streamed to the caller without blocking the Worker Thread. It is fast and the user gets the result as soon as the first data node is retrieved from the database.

await foreach(var post in _context.Posts.Include(e => e.Tags)){
Console.WriteLine(post);
foreach(var tags in post.Tags){
Console.WrirteLine(tags);
}
}

2. You can use ArrayPool<T>.Shared.Rent(100); to minimize object allocation on the Heap (the less the Garbage Collect collects the better performant your application becomes) See code below. Read about how Garbage Collection works here.

var arraypool = ArrayPool<Bills>.Shared.Rent(50);

try{
//Do your work here
}Finally{
ArrayPool<Bill>.Shared.Return(arrayPool);
}

3. Use Stack Alloc in C# to create a short-lived variable. 
  - Spans are more than just a way to access subset arrays. They can also be used to refer to data on the stack. 

     Span<byte> b = stackalloc byte[2];
     b[0] = 42; //Will allocate the 42 on the Stack. But b[0] can not be access outside the function, only short lived within the function.



4. Use the "try" and "finally" code directive and all objects instantiated, the "finally" block cleans up before the execution leaves the function.

try{

//Code

}catch(MakeSureYouCatchSpecificExceptionHere error) when (conditionHereIfYouWant){
//take action or you can throw :)

}catch(MakeSureYouCatchSpecificExceptionHere error) when (conditionHereIfYouWant){
//take action or you can throw :)

}finally{
//cleans up allocated Objects in Memory
}



//Or use Try Finally directives

try{
//Code
}finally{
//cleans up allocated Objects in Memory
}

 

 



6/14/21 [C# 9 Language Feature]
1. Did you know you could write code like so, newer version of C# has made it really easy for the syntax to look and sound like day to day speaking English Language:

   if(MyVariable is not null and MyOtherVariable is null)

6/9/21
1. Registering the Database Context as Singleton in the Startup class has some consequences. Every time you try to retrieve the Entity and do some operations on it then try to SaveChanges(); an error most of the time occurred. 
Error: InvalidOperaton: Cannot track the Entity Type 'yourEntityHere' because it is being tracked by another instance of this Context.

Entity Framework not Saving Changed Entity State to the Database
1. When EF Core does not persist or save changes to the Database after calling SaveChanges function is called,
    do:

_context.ChangeTracker.AutoDetectChangesEnabled = true;


     before calling

_context.SaveChanges()

6/3/2021: Use Array.Copy

1. Use Array.Copy to create a shallow copy of the list or array to work with. This does not create the object on the Heap or possibly push the object to Gen 1 and Gen 2 Memory buckets that cause the GC to kick up.

2. Use CompareTo(string or int) to compare two object values, 0 means Yes, and 1 means no.




6/2/21: Did you Know [HotChocolate] library
1. Did you know that you could actually inject a service on a Field Level? on a Property Level
   e.g.

public IQueryable<Book> getBook([Service] DatabaseContext _context); 
//You could do this in the Interface and get access to the DatabaseContext Service through the field you have just initialized.







6/2/21: Understanding Span<T> (Span of T)

1. You can only use span in the function context, this prevents the Compiler from allocating another object in memory that might end up on the HEAP and eventually on Gen2 Memory HEAP. When an object a big it ends up getting allocated on Gen2 Memory HEAP the Garbage Collecter might at some get triggered to clean up resources/memory. When this happens Performance of an application suffers.

- The reason for working with Spans is that you rent memory on the STACK, when you complete using the slice then the memory is freed right away. That is why you can't access the Span Object outside the function, when the function is complete all objects utilized inside that function get disposed of.

2. Use Array Pooling if possible, this prevents the unnecessary creation of big objects on the HEAP, instead of when you want to use some sort of a Collection you rent the space from the Array Pool of T, and when you are done, retain it.

- Be careful sometimes when you rent the Array space might contain something it, and the idea of emptying the space every time you rent and use the Array pool would be costly.






6/1/2021

1. Enumerating the List Asynchronously: Add an Await in front of the "foreach" to enumerate through the list as data become available





5/25/21 [Dealing with File IO Exception]

1. If you have code that writes and reads from a file, you might experience IO Exception that writing to the file was not successful due to the file being in Use.
     In order to resolve this, check to see if the file is in use first before writing to it. 
   

 try{

          FileStream st = file.Open(FileMode.Open,fileAccess.Read, FileShare.None)
         }catch(IOException ex){
           return true;
      }



- Also if you want to log the exception, instead of logging the ex.Message log ex.StackTrace to get more information about the error.


5/24/21: Wisdom learned through experience

1. When building the C# Asp.Net 5 Application, not all functions or code should be implemented nor utilize Async Await directives.
    - I found out that the response or the results of the Async function is not guaranteed as this would cause inconsistencies. We don't know if the operation succeeded or not.
       In the case of writing to the file in the Function, when we call an Async Function that writes to the file, sometimes the execution won't complete since the code utilizes Async Await, if you haven't Awaited the Request, the code execution in the present/current function will go on executing and might call another function that overrides the Business Logic needed for the function that writes to the file to complete its operation.
- The best way is to observe the situation and see if it is appropriate to implement Async Await.
- [update]: I also found out that combining Async calling with non-Async calling of function inside the Async function produces really weird results. 
                        This is because if the Async function is called along with the none Async function both execution will be executed at different times and the dependencies will be messed up.
                   - Solution:
Make sure you have two functions one that utilizes the Async and another that does not, when you decide to use an Async and return a Task from your function try by all means to only call the Async function and make sure to Await the results of every request.


1. I have seen code with fewer or equal symbols embedded into the c# code.

2. I have seen code with the Not-Equal-to symbol embedded into the c# code
3. I have seen code written as (null != variable) instead of the other way round.

Delegates (Decaples the framework code from business logic)

1. Delegates are a pointer to a function (keep in mind that they delegate the work to any function that has the same signature)
2. Just like Classes, a delegate is created using a "delegate" keyword and can be instantiated.
3. A Delegate can not be created inside a class, it is a standalone file or instance just like the Class.
      - the way you instantiate a delegate is as below:

public delegate void MyNiceDelegate(param1,param2);

public class MyClass{
Main(){
MyNiceDelegate d = new MyNiceDelegate(NiceFunctionToDelegateTo)
};

public void NiceFunctionToDelegateTo(param1,param2){
//Do Stuff
}
}

3. The reason for a delegate is when you want to make your library flexible enough, let's say you want a user (developer) to define their own functions that return the same type as the delegate but have owner/developer business logic but return true or false then the delegate passes true or false to a hidden abstracted library a developer does have access to change code to.

4. Avoids the library Developer from hardcoding the business logic into a function, that way the caller will have to specify a function that returns the same type as the delegate. This way a developer has more freedom in defining their own business logic.

5. You can use an inline lambda expression instead of creating an instance of a delegate






References:


Added by AI:

Here are some tips and tricks for developing in C#:

  1. Use the latest version of C#: C# is constantly evolving, and new versions often come with new language features that can simplify your code or improve performance.

  2. Use Object-Oriented Programming principles: C# is an object-oriented language, and using OOP principles like inheritance, encapsulation, and polymorphism can make your code more organized and easier to maintain.

  3. Use Visual Studio: Visual Studio is a powerful Integrated Development Environment (IDE) that provides many helpful tools for C# developers, such as debugging, IntelliSense, and code refactoring.

  4. Follow coding standards: Use a consistent coding style and adhere to industry-recognized coding standards like Microsoft's C# Coding Conventions to make your code more readable and maintainable.

  5. Use generics: Generics allow you to write type-safe code that can work with any data type, improving your code's flexibility and reusability.

  6. Use LINQ: LINQ (Language Integrated Query) is a powerful tool that allows you to query and manipulate data in a more concise and expressive way.

  7. Use async/await: Asynchronous programming can improve the performance of your applications by allowing multiple tasks to run simultaneously without blocking the main thread.

  8. Use interfaces: Interfaces allow you to define a contract for a set of related classes, making your code more modular and easier to test.

  9. Write unit tests: Unit testing helps ensure that your code works as expected and makes it easier to detect bugs and regressions as you continue to develop your code.

  10. Continuously learn and improve: C# is a constantly evolving language, and staying up-to-date with new language features and best practices can help you write better code and improve your skills as a developer.





Research
published
v.0.01



Mark said:

Can you update this article?

Posted On: January 08, 2023 8:51:58 AM


For peering opportunity Autonomouse System Number: AS401345 Custom Software Development at ErnesTech Email Address[email protected]