Skip to content

Commit 4ffb63a

Browse files
authored
Merge pull request #14 from yurkinh/Refactors
Some refactors
2 parents 5ae9554 + f885d42 commit 4ffb63a

26 files changed

+4198
-308
lines changed

.github/copilot-instructions.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
## Prerequisites
2+
1. Install the latest stable [.NET SDK](https://dotnet.microsoft.com/en-us/download).
3+
2. Install .NET MAUI workloads (we recommend using Visual Studio installer).
4+
5+
## Setting Up GitHub Copilot
6+
1. Ensure you have GitHub Copilot installed and enabled in Visual Studio.
7+
2. Familiarize yourself with the basic usage of GitHub Copilot by reviewing the (official documentation)[https://docs.github.com/en/copilot].
8+
9+
## Writing Code with GitHub Copilot
10+
### General Guidelines
11+
* Use GitHub Copilot to assist with code completion, documentation, and generating boilerplate code.
12+
* Always review and test the code suggested by GitHub Copilot to ensure it meets the project's standards and requirements.
13+
14+
### Specific to .NET MAUI
15+
* Ensure that any UI components or controls are compatible with .NET MAUI.
16+
* Avoid using Xamarin.Forms-specific code unless there is a direct .NET MAUI equivalent.
17+
* Follow the project's coding style and best practices as outlined in the (contributing)[https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md] document.
18+
19+
## Best Practices
20+
* Use **Trace.WriteLine()** for debug logging instead of **Debug.WriteLine()**.
21+
* Include a **CancellationToken** as a parameter for methods returning **Task** or **ValueTask**.
22+
* Use **is** for null checking and type checking.
23+
* Use file-scoped namespaces to reduce code verbosity.
24+
* Avoid using the **!** null forgiving operator.
25+
* Follow naming conventions for enums and property names.
26+
27+
### Debug Logging
28+
* Always use `Trace.WriteLine()` instead of `Debug.WriteLine` for debug logging because `Debug.WriteLine` is removed by the compiler in Release builds
29+
30+
### Methods Returning Task and ValueTask
31+
* Always include a `CancellationToken` as a parameter to every method returning `Task` or `ValueTask`
32+
* If the method is public, provide a the default value for the `CancellationToken` (e.g. `CancellationToken token = default`)
33+
* If the method is not public, do not provide a default value for the `CancellationToken`
34+
* If the method is used outside of a .net MAUI control, Use `CancellationToken.ThrowIfCancellationRequested()` to verify the `CancellationToken`, as it is not possible to catch exceptions in XAML.
35+
36+
### Enums
37+
* Always use `Unknown` at index 0 for return types that may have a value that is not known
38+
* Always use `Default` at index 0 for option types that can use the system default option
39+
* Follow naming guidelines for tense... `SensorSpeed` not `SensorSpeeds`
40+
* Assign values (0,1,2,3) for all enums, if not marked with a `Flags` attribute. This is to ensure that the enum can be serialized and deserialized correctly across platforms.
41+
42+
### Property Names
43+
* Include units only if one of the platforms includes it in their implementation. For instance HeadingMagneticNorth implies degrees on all platforms, but PressureInHectopascals is needed since platforms don't provide a consistent API for this.
44+
45+
### Units
46+
* Use the standard units and most well accepted units when possible. For instance Hectopascals are used on UWP/Android and iOS uses Kilopascals so we have chosen Hectopascals.
47+
48+
### Pattern matching
49+
#### Null checking
50+
* Prefer using `is` when checking for null instead of `==`.
51+
52+
e.g.
53+
54+
```csharp
55+
// null
56+
if (something is null)
57+
{
58+
59+
}
60+
61+
// or not null
62+
if (something is not null)
63+
{
64+
65+
}
66+
```
67+
68+
* Avoid using the `!` [null forgiving operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving) to avoid the unintended introduction of bugs.
69+
70+
#### Type checking
71+
* Prefer `is` when checking for types instead of casting.
72+
73+
e.g.
74+
75+
```csharp
76+
if (something is Bucket bucket)
77+
{
78+
bucket.Empty();
79+
}
80+
```
81+
82+
### Use collection initializers or expressions
83+
* Use [Use collection initializers or expressions](https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/style-rules/ide0028) Use collection initializers or expressions.
84+
85+
e.g.
86+
87+
```csharp
88+
List<int> list = [1, 2, 3];
89+
List<int> list = [];
90+
```
91+
92+
### File Scoped Namespaces
93+
* Use [file scoped namespaces](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/file-scoped-namespaces) to help reduce code verbosity.
94+
95+
e.g.
96+
97+
```csharp
98+
namespace CommunityToolkit.Maui.Converters;
99+
100+
using System;
101+
102+
class BoolToObjectConverter
103+
{
104+
}
105+
```
106+
107+
### Braces
108+
Please use `{ }` after `if`, `for`, `foreach`, `do`, `while`, etc.
109+
110+
e.g.
111+
112+
```csharp
113+
if (something is not null)
114+
{
115+
ActOnIt();
116+
}
117+
```
118+
119+
### `NotImplementedException`
120+
* Please avoid adding new code that throws a `NotImplementedException`. According to the [Microsoft Docs](https://docs.microsoft.com/dotnet/api/system.notimplementedexception), we should only "throw a `NotImplementedException` exception in properties or methods in your own types when that member is still in development and will only later be implemented in production code. In other words, a NotImplementedException exception should be synonymous with 'still in development.'"
121+
In other words, `NotImplementedException` implies that a feature is still in development, indicating that the Pull Request is incomplete.
122+
123+
### Bug Fixes
124+
If you're looking for something to fix, please browse [open issues](https://github.com/CommunityToolkit/Maui/issues).
125+
126+
Follow the style used by the [.NET Foundation](https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md), with two primary exceptions:
127+
128+
* We do **not** use the `private` keyword as it is the default accessibility level in C#.
129+
* We will **not** use `_` or `s_` as a prefix for internal or private field names
130+
* We will use `camelCaseFieldName` for naming internal or private fields in both instance and static implementations
131+
132+
Read and follow our [Pull Request template](https://github.com/CommunityToolkit/Maui/blob/main/.github/PULL_REQUEST_TEMPLATE.md)
133+
134+
## Submitting Contributions
135+
1. Fork the repository and create a new branch for your changes.
136+
2. Implement your changes using GitHub Copilot as needed.
137+
3. Ensure your changes include tests, samples, and documentation.
138+
4. Open a pull request and follow the [Pull Request template](https://github.com/CommunityToolkit/Maui/blob/main/.github/PULL_REQUEST_TEMPLATE.md).
139+
140+
## Additional Resources
141+
- (GitHub Copilot Documentation)[https://docs.github.com/en/copilot]
142+
- [.NET MAUI Documentation](https://learn.microsoft.com/en-us/dotnet/maui/)
143+
144+
By following these guidelines, you can effectively use GitHub Copilot to contribute to the .NET MAUI Community Toolkit. Thank you for your contributions!
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Async Programming Best Practices
2+
3+
This cheat sheet should serve as a quick reminder of best practices when writing asynchronous code. Following these guidelines will help you avoid common pitfalls such as unobserved exceptions, deadlocks, and unexpected UI blocking.
4+
5+
## DOs
6+
- **Always Await Your Tasks:**
7+
Always use the `await` keyword on async operations to ensure exceptions are captured and to avoid blocking the calling thread.
8+
- **Use Async Task/Task<T> Methods:**
9+
Prefer returning `Task` or `Task<T>` over `async void` so that exceptions can be observed, and methods are easily composable and testable.
10+
- **Name Methods with the "Async" Suffix:**
11+
Clearly differentiate asynchronous methods (e.g., `GetDataAsync()`) from synchronous ones, if there's a synchronous counterpart.
12+
- **Pass Cancellation Tokens:**
13+
Allow cancellation by accepting a `CancellationToken` in async methods.
14+
- **Use ConfigureAwait(false) When Appropriate:**
15+
In library code use `ConfigureAwait(false)` to avoid unnecessary context switches and potential deadlocks.
16+
- **Keep Async Code “Async All the Way”:**
17+
Propagate async all the way from the entry point (like event handlers or controller actions) rather than mixing sync and async code.
18+
- **Report Progress and Handle Exceptions Properly:**
19+
Use tools like `IProgress<T>` to report progress and always catch exceptions at the appropriate level when awaiting tasks.
20+
21+
## DON'Ts
22+
- **Avoid async void Methods:**
23+
Except for event handlers and overriding methods, never use `async void` because their exceptions are not observable and they're difficult to test.
24+
- **Don't Block on Async Code:**
25+
Avoid using `.Wait()` or `.Result` as these can lead to deadlocks and wrap exceptions in `AggregateException`. If you must block, consider using `GetAwaiter().GetResult()`.
26+
- **Don't Mix Blocking and Async Code:**
27+
Blocking the calling thread in an otherwise async flow (e.g., by mixing synchronous calls with async ones) may cause deadlocks and performance issues.
28+
- **Avoid Wrapping Return Task in Try/Catch or Using Blocks:**
29+
When a method returns a `Task`, wrapping it in a try/catch or using block may lead to unexpected behaviour because the task completes outside those blocks. For these scenarios use `async/await`.
30+
- **Don't Overuse Fire-and-Forget Patterns:**
31+
Unobserved tasks (fire-and-forget) can swallow exceptions and cause race conditions—if needed, use a “safe fire-and-forget” pattern with proper error handling.
32+

0 commit comments

Comments
 (0)