← スキル一覧に戻る
The

code-standards
by erymuzuan
Motorbike rental system for Thailand tourist areas (Phuket, Krabi, etc.) - Blazor Server + WASM PWA with MudBlazor
⭐ 0🍴 0📅 2026年1月24日
SKILL.md
name: code-standards description: C# coding conventions, naming patterns, and file organization standards for the MotoRent project.
Code Standards
C# Coding Standards
- Framework: .NET 10
- Language Version: C# 14 or latest
- Nullable Reference Types: Enabled
- Pattern: Use modern C# features (pattern matching, records, init-only properties)
- Async/Await: Prefer async methods for I/O operations
- Naming Conventions:
- PascalCase for classes, methods, properties
- camelCase for local variables and parameters
- Prefix interfaces with
I - Prefix for private instance members is
m_ - Prefix for static fields is
m_ - Prefix for constants UPPERCASE_WITH_UNDERSCORES
Service Injection Pattern
// In ServicesExtensions.cs
builder.Services.AddScoped<IMotorbikeService, MotorbikeService>();
services.AddSingleton<IRepository<Motorbike>, SqlJsonRepository<Motorbike>>();
// use constructor injection
// ALWAYS use "this" keyword when referencing any instance member of the current class
// ALWAYS use "base" keyword when referencing any base class member
public class MotorbikeService(RentalDataContext context) : IMotorbikeService
{
// use private get property
private RentalDataContext Context {get;} = context;
public async Task DoSomethingAsync(int id)
{
// do NOT omit `this` keyword
var motorbike = await this.Context.LoadOneAsync<Motorbike>(m => m.MotorbikeId == id);
// the rest of the code
if (SelectedShopId > 0 && rc.ShopId != SelectedShopId) // WRONG
if (this.SelectedShopId > 0 && rc.ShopId != this.SelectedShopId) // CORRECT
}
}
Pattern Matching
var boolVar = isTrue ? "yes" : "no";
// for a simple boolean, but when isTrue is complex expression, use pattern
var result = someValue switch
{
> 0 => "positive",
< 0 => "negative",
_ => "zero"
};
File Organization
// 1. Usings (sorted, no unnecessary)
using System.Text.Json;
using MotoRent.Domain.Entities;
// 2. Namespace
namespace MotoRent.Services;
// 3. Type declaration
public class RentalService(RentalDataContext context)
{
// 4. Constants
private const int MAX_RENTAL_DAYS = 30;
// 5. Static fields
private static readonly JsonSerializerOptions s_options = new();
// private properties for injection
private RentalDataContext {get;} = context;
// 6. Instance fields (m_ prefix)
private List<Rental> m_cachedRentals = [];
// 8. Properties
public int ShopId { get; set; }
// 9. Public methods
public async Task<Rental?> GetRentalAsync(int id)
{
return await this.DataContext.LoadOneAsync<Rental>(r => r.RentalId == id);
}
// 9. One line methods
public Task<Rental?> GetRentalAsync(int id) => this.DataContext.LoadOneAsync<Rental>(r => r.RentalId == id);
// 11. Private methods
private void ValidateRental(Rental rental)
{
// ...
}
// DO NOT user #region and #endregion, instead use partial class for example:
// Rental.search.cs for search related members
// Rental.validation.cs for validation rules etc
}
Expression-Bodied Members
// Properties
public int RentalId { get; set; }
public string FullName => $"{this.FirstName} {this.LastName}";
// Methods (single expression)
public override int GetId() => this.RentalId;
public override void SetId(int value) => this.RentalId = value;
// Methods (multiple statements - use block body)
public async Task SaveAsync()
{
using var session = this.m_context.OpenSession();
session.Attach(this);
await session.SubmitChanges("Save");
}
Null Handling
// Nullable reference types (enabled in project)
public string? OptionalField { get; set; }
public string RequiredField { get; set; } = string.Empty;
// Null checks
if (rental is null)
return;
// Pattern matching
if (rental is { Status: "Active" })
ProcessActive(rental);
if (shop == null || !shop.IsActive) // Wrong
if( shop is {IsActive:true}) // correct
// Null coalescing
var name = rental?.RenterName ?? "Unknown";
// Null-forgiving (only when certain)
var item = list.FirstOrDefault()!;
Collections
// Use collection expressions
private List<Rental> Rentals {get;} = [];
private Dictionary<int, Rental> Cache {get;} = [];
// LINQ patterns
var query = this.DataContext.CreateQuery<Rental>()
.Where(r => r.Status == "Active")
.OrderByDescending(r => r.StartDate);
var lo = await this.DataContext.LoadAsync(query);
var rentals = lo.ItemCollection;
// Prefer foreach for side effects
foreach (var rental in rentals)
{
rental.Status = "Completed";
}
Async/Await
// Always use async suffix
public async Task<Rental?> LoadRentalAsync(int id)
// Always await or return
public async Task ProcessAsync()
{
// other statements
await this.DoWorkAsync();
}
// Fire and forget (rare, use with caution)
_ = Task.Run(async () => await this.BackgroundWorkAsync());
// Parallel operations
await Task.WhenAll(
this.LoadRentalsAsync(),
this.LoadMotorbikesAsync(),
this.LoadRentersAsync()
);
Entity Patterns
public class Rental : Entity
{
// Primary key
public int RentalId { get; set; }
// Foreign keys
public int ShopId { get; set; }
public int RenterId { get; set; }
public int MotorbikeId { get; set; }
// Required strings
public string Status { get; set; } = "Reserved";
// Optional strings
public string? Notes { get; set; }
// Dates
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset? ActualEndDate { get; set; }
// Money
public decimal DailyRate { get; set; }
public decimal TotalAmount { get; set; }
// Entity base implementation
public override int GetId() => this.RentalId;
public override void SetId(int value) => this.RentalId = value;
}
Error Handling
// Use try-catch for expected errors
try
{
await this.ProcessRentalAsync(rental);
}
catch (ValidationException ex)
{
this.ToastService.ShowWarning(ex.Message);
}
catch (Exception ex)
{
this.Logger.LogError(ex, "Failed to process rental {RentalId}", rental.RentalId);
this.ToastService.ShowError("An error occurred");
}
// Throw for programming errors
if (rental is null)
throw new ArgumentNullException(nameof(rental));
Comments
// Single-line for brief explanations
// Calculate total including insurance
/// <summary>
/// XML doc for public APIs
/// </summary>
/// <param name="rentalId">The rental identifier</param>
/// <returns>The rental or null if not found</returns>
public async Task<Rental?> GetRentalAsync(int rentalId)
// Avoid obvious comments
// BAD: Increment counter
// GOOD: (no comment needed for i++)
The this Keyword Rule (IMPORTANT)
Always use this when referencing instance members:
// WRONG - missing this keyword
m_loading = true;
DataContext.LoadAsync(query);
ShowSuccess("Saved");
// CORRECT - always use this
this.m_loading = true;
this.DataContext.LoadAsync(query);
this.ShowSuccess("Saved");
This applies to:
- Private fields (
this.m_field) - Properties (
this.PropertyName) - Methods (
this.MethodName()) - Injected services (
this.DataContext,this.DialogService)
Why?
- Clearer distinction between local variables and instance members
- Prevents accidental shadowing
- Consistent with rx-erp codebase patterns
- Easier to identify dependencies in code
Source
- Based on:
E:\project\work\rx-erppatterns - Microsoft C# Coding Conventions
Blazor & Razor files
Use blazor development skill and css styling skill
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です