@ngxtm/devkit 3.3.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/index.js +59 -13
- package/cli/rules.js +248 -0
- package/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# Blazor Reference
|
|
2
|
+
|
|
3
|
+
Component lifecycle, state management, and advanced patterns.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Lifecycle**](lifecycle.md) - Component lifecycle methods.
|
|
8
|
+
- [**State Management**](state-management.md) - Fluxor, cascading values.
|
|
9
|
+
- [**JS Interop**](js-interop.md) - JavaScript interoperability.
|
|
10
|
+
|
|
11
|
+
## Component Lifecycle
|
|
12
|
+
|
|
13
|
+
```csharp
|
|
14
|
+
@code {
|
|
15
|
+
// 1. Called when component is first initialized (before rendering)
|
|
16
|
+
protected override void OnInitialized()
|
|
17
|
+
{
|
|
18
|
+
// Sync initialization
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 1b. Async version (preferred for data loading)
|
|
22
|
+
protected override async Task OnInitializedAsync()
|
|
23
|
+
{
|
|
24
|
+
// Load initial data
|
|
25
|
+
_data = await DataService.GetAsync();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Called when parameters are set/changed
|
|
29
|
+
protected override void OnParametersSet()
|
|
30
|
+
{
|
|
31
|
+
// React to parameter changes
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected override async Task OnParametersSetAsync()
|
|
35
|
+
{
|
|
36
|
+
// Async parameter processing
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 3. Called after component has rendered
|
|
40
|
+
protected override void OnAfterRender(bool firstRender)
|
|
41
|
+
{
|
|
42
|
+
if (firstRender)
|
|
43
|
+
{
|
|
44
|
+
// First render only - initialize JS libraries
|
|
45
|
+
}
|
|
46
|
+
// Every render - update DOM-dependent state
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
50
|
+
{
|
|
51
|
+
if (firstRender)
|
|
52
|
+
{
|
|
53
|
+
await JSRuntime.InvokeVoidAsync("initializeChart", _chartElement);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 4. Optimize re-rendering
|
|
58
|
+
protected override bool ShouldRender()
|
|
59
|
+
{
|
|
60
|
+
// Return false to prevent re-rendering
|
|
61
|
+
return _hasChanged;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 5. Cleanup when component is disposed
|
|
65
|
+
public void Dispose()
|
|
66
|
+
{
|
|
67
|
+
// Unsubscribe from events, dispose resources
|
|
68
|
+
_subscription?.Dispose();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Async dispose (IAsyncDisposable)
|
|
72
|
+
public async ValueTask DisposeAsync()
|
|
73
|
+
{
|
|
74
|
+
await JSRuntime.InvokeVoidAsync("cleanup");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## State Management Patterns
|
|
80
|
+
|
|
81
|
+
```csharp
|
|
82
|
+
// 1. Cascading Values - App-wide state
|
|
83
|
+
// App.razor or Routes.razor
|
|
84
|
+
<CascadingValue Value="@_themeState">
|
|
85
|
+
<CascadingValue Value="@_userState">
|
|
86
|
+
<Router AppAssembly="@typeof(App).Assembly">
|
|
87
|
+
...
|
|
88
|
+
</Router>
|
|
89
|
+
</CascadingValue>
|
|
90
|
+
</CascadingValue>
|
|
91
|
+
|
|
92
|
+
@code {
|
|
93
|
+
private ThemeState _themeState = new();
|
|
94
|
+
private UserState _userState = new();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Consuming component
|
|
98
|
+
@code {
|
|
99
|
+
[CascadingParameter]
|
|
100
|
+
public ThemeState Theme { get; set; } = default!;
|
|
101
|
+
|
|
102
|
+
[CascadingParameter]
|
|
103
|
+
public UserState User { get; set; } = default!;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```csharp
|
|
108
|
+
// 2. State Container Service
|
|
109
|
+
public class CartState
|
|
110
|
+
{
|
|
111
|
+
private readonly List<CartItem> _items = [];
|
|
112
|
+
|
|
113
|
+
public IReadOnlyList<CartItem> Items => _items.AsReadOnly();
|
|
114
|
+
public decimal Total => _items.Sum(i => i.Price * i.Quantity);
|
|
115
|
+
|
|
116
|
+
public event Action? OnChange;
|
|
117
|
+
|
|
118
|
+
public void AddItem(CartItem item)
|
|
119
|
+
{
|
|
120
|
+
_items.Add(item);
|
|
121
|
+
NotifyStateChanged();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public void RemoveItem(int productId)
|
|
125
|
+
{
|
|
126
|
+
_items.RemoveAll(i => i.ProductId == productId);
|
|
127
|
+
NotifyStateChanged();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private void NotifyStateChanged() => OnChange?.Invoke();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Registration
|
|
134
|
+
builder.Services.AddScoped<CartState>();
|
|
135
|
+
|
|
136
|
+
// Component usage
|
|
137
|
+
@inject CartState Cart
|
|
138
|
+
@implements IDisposable
|
|
139
|
+
|
|
140
|
+
<div>Total: @Cart.Total.ToString("C")</div>
|
|
141
|
+
|
|
142
|
+
@code {
|
|
143
|
+
protected override void OnInitialized()
|
|
144
|
+
{
|
|
145
|
+
Cart.OnChange += StateHasChanged;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public void Dispose()
|
|
149
|
+
{
|
|
150
|
+
Cart.OnChange -= StateHasChanged;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```csharp
|
|
156
|
+
// 3. Fluxor (Redux pattern)
|
|
157
|
+
// State
|
|
158
|
+
public record CounterState(int Count);
|
|
159
|
+
|
|
160
|
+
public class CounterFeature : Feature<CounterState>
|
|
161
|
+
{
|
|
162
|
+
public override string GetName() => "Counter";
|
|
163
|
+
protected override CounterState GetInitialState() => new(0);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Actions
|
|
167
|
+
public record IncrementAction();
|
|
168
|
+
public record DecrementAction();
|
|
169
|
+
public record SetCountAction(int Count);
|
|
170
|
+
|
|
171
|
+
// Reducers
|
|
172
|
+
public static class CounterReducers
|
|
173
|
+
{
|
|
174
|
+
[ReducerMethod]
|
|
175
|
+
public static CounterState OnIncrement(CounterState state, IncrementAction _)
|
|
176
|
+
=> state with { Count = state.Count + 1 };
|
|
177
|
+
|
|
178
|
+
[ReducerMethod]
|
|
179
|
+
public static CounterState OnDecrement(CounterState state, DecrementAction _)
|
|
180
|
+
=> state with { Count = state.Count - 1 };
|
|
181
|
+
|
|
182
|
+
[ReducerMethod]
|
|
183
|
+
public static CounterState OnSetCount(CounterState state, SetCountAction action)
|
|
184
|
+
=> state with { Count = action.Count };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Component
|
|
188
|
+
@inject IState<CounterState> CounterState
|
|
189
|
+
@inject IDispatcher Dispatcher
|
|
190
|
+
|
|
191
|
+
<p>Count: @CounterState.Value.Count</p>
|
|
192
|
+
<button @onclick="Increment">+</button>
|
|
193
|
+
<button @onclick="Decrement">-</button>
|
|
194
|
+
|
|
195
|
+
@code {
|
|
196
|
+
private void Increment() => Dispatcher.Dispatch(new IncrementAction());
|
|
197
|
+
private void Decrement() => Dispatcher.Dispatch(new DecrementAction());
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## JS Interop
|
|
202
|
+
|
|
203
|
+
```csharp
|
|
204
|
+
// Calling JavaScript from C#
|
|
205
|
+
@inject IJSRuntime JS
|
|
206
|
+
|
|
207
|
+
@code {
|
|
208
|
+
private ElementReference _inputElement;
|
|
209
|
+
|
|
210
|
+
// Call JS function
|
|
211
|
+
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
212
|
+
{
|
|
213
|
+
if (firstRender)
|
|
214
|
+
{
|
|
215
|
+
await JS.InvokeVoidAsync("initializeComponent", _inputElement);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Call JS function with return value
|
|
220
|
+
private async Task<string> GetLocalStorage(string key)
|
|
221
|
+
{
|
|
222
|
+
return await JS.InvokeAsync<string>("localStorage.getItem", key);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Focus element
|
|
226
|
+
private async Task FocusInput()
|
|
227
|
+
{
|
|
228
|
+
await _inputElement.FocusAsync();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// wwwroot/js/interop.js
|
|
235
|
+
window.initializeComponent = (element) => {
|
|
236
|
+
// Initialize third-party library
|
|
237
|
+
new SomeLibrary(element);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
window.blazorInterop = {
|
|
241
|
+
showAlert: (message) => alert(message),
|
|
242
|
+
getWindowSize: () => ({ width: window.innerWidth, height: window.innerHeight })
|
|
243
|
+
};
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```csharp
|
|
247
|
+
// Calling C# from JavaScript
|
|
248
|
+
// In component
|
|
249
|
+
@inject IJSRuntime JS
|
|
250
|
+
|
|
251
|
+
@code {
|
|
252
|
+
private DotNetObjectReference<MyComponent>? _objRef;
|
|
253
|
+
|
|
254
|
+
protected override void OnInitialized()
|
|
255
|
+
{
|
|
256
|
+
_objRef = DotNetObjectReference.Create(this);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
260
|
+
{
|
|
261
|
+
if (firstRender)
|
|
262
|
+
{
|
|
263
|
+
await JS.InvokeVoidAsync("registerCallback", _objRef);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
[JSInvokable]
|
|
268
|
+
public void HandleCallback(string data)
|
|
269
|
+
{
|
|
270
|
+
// Called from JavaScript
|
|
271
|
+
Console.WriteLine($"Received: {data}");
|
|
272
|
+
StateHasChanged();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public void Dispose()
|
|
276
|
+
{
|
|
277
|
+
_objRef?.Dispose();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
```javascript
|
|
283
|
+
// JavaScript calling C#
|
|
284
|
+
window.registerCallback = (dotNetRef) => {
|
|
285
|
+
window.myCallback = (data) => {
|
|
286
|
+
dotNetRef.invokeMethodAsync('HandleCallback', data);
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// Later...
|
|
291
|
+
myCallback('Some data from JS');
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Render Modes (.NET 8+)
|
|
295
|
+
|
|
296
|
+
```razor
|
|
297
|
+
@* Static Server Rendering (SSR) - Default *@
|
|
298
|
+
@rendermode InteractiveServer
|
|
299
|
+
@rendermode InteractiveWebAssembly
|
|
300
|
+
@rendermode InteractiveAuto
|
|
301
|
+
|
|
302
|
+
@* Per-component render mode *@
|
|
303
|
+
<Counter @rendermode="InteractiveServer" />
|
|
304
|
+
<Counter @rendermode="InteractiveWebAssembly" />
|
|
305
|
+
|
|
306
|
+
@* Streaming rendering for slow data *@
|
|
307
|
+
@attribute [StreamRendering]
|
|
308
|
+
|
|
309
|
+
<h1>Dashboard</h1>
|
|
310
|
+
|
|
311
|
+
@if (_data is null)
|
|
312
|
+
{
|
|
313
|
+
<p>Loading dashboard data...</p>
|
|
314
|
+
}
|
|
315
|
+
else
|
|
316
|
+
{
|
|
317
|
+
<DashboardContent Data="_data" />
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@code {
|
|
321
|
+
private DashboardData? _data;
|
|
322
|
+
|
|
323
|
+
protected override async Task OnInitializedAsync()
|
|
324
|
+
{
|
|
325
|
+
// This data streams to the client as it loads
|
|
326
|
+
_data = await SlowDataService.GetDashboardAsync();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Error Handling
|
|
332
|
+
|
|
333
|
+
```razor
|
|
334
|
+
@* ErrorBoundary for graceful error handling *@
|
|
335
|
+
<ErrorBoundary @ref="_errorBoundary">
|
|
336
|
+
<ChildContent>
|
|
337
|
+
<RiskyComponent />
|
|
338
|
+
</ChildContent>
|
|
339
|
+
<ErrorContent Context="exception">
|
|
340
|
+
<div class="alert alert-danger">
|
|
341
|
+
<h4>Something went wrong</h4>
|
|
342
|
+
<p>@exception.Message</p>
|
|
343
|
+
<button @onclick="Recover">Try Again</button>
|
|
344
|
+
</div>
|
|
345
|
+
</ErrorContent>
|
|
346
|
+
</ErrorBoundary>
|
|
347
|
+
|
|
348
|
+
@code {
|
|
349
|
+
private ErrorBoundary? _errorBoundary;
|
|
350
|
+
|
|
351
|
+
private void Recover()
|
|
352
|
+
{
|
|
353
|
+
_errorBoundary?.Recover();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Authentication in Blazor
|
|
359
|
+
|
|
360
|
+
```razor
|
|
361
|
+
@* Show content based on auth state *@
|
|
362
|
+
<AuthorizeView>
|
|
363
|
+
<Authorized>
|
|
364
|
+
<p>Hello, @context.User.Identity?.Name!</p>
|
|
365
|
+
<a href="account/logout">Logout</a>
|
|
366
|
+
</Authorized>
|
|
367
|
+
<NotAuthorized>
|
|
368
|
+
<a href="account/login">Login</a>
|
|
369
|
+
</NotAuthorized>
|
|
370
|
+
</AuthorizeView>
|
|
371
|
+
|
|
372
|
+
@* Role-based content *@
|
|
373
|
+
<AuthorizeView Roles="Admin,Manager">
|
|
374
|
+
<Authorized>
|
|
375
|
+
<AdminPanel />
|
|
376
|
+
</Authorized>
|
|
377
|
+
<NotAuthorized>
|
|
378
|
+
<p>Access denied</p>
|
|
379
|
+
</NotAuthorized>
|
|
380
|
+
</AuthorizeView>
|
|
381
|
+
|
|
382
|
+
@* Policy-based content *@
|
|
383
|
+
<AuthorizeView Policy="CanEditOrders">
|
|
384
|
+
<button @onclick="EditOrder">Edit</button>
|
|
385
|
+
</AuthorizeView>
|
|
386
|
+
|
|
387
|
+
@* Protect entire page *@
|
|
388
|
+
@page "/admin"
|
|
389
|
+
@attribute [Authorize(Roles = "Admin")]
|
|
390
|
+
|
|
391
|
+
<h1>Admin Dashboard</h1>
|
|
392
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: C# Language Patterns
|
|
3
|
+
description: Modern C# standards for type safety, performance, and maintainability.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [csharp, dotnet, language, types, async]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.cs', '**/*.csproj']
|
|
8
|
+
keywords: [class, record, interface, async, await, linq, nullable, span]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# C# Language Patterns
|
|
12
|
+
|
|
13
|
+
## **Priority: P0 (CRITICAL)**
|
|
14
|
+
|
|
15
|
+
Modern C# standards for type-safe, performant, maintainable code.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **Nullable Reference Types**: Enable `<Nullable>enable</Nullable>`. Use `?` for nullable, avoid `!` except when compiler can't infer.
|
|
20
|
+
- **Records**: `record` for immutable DTOs, `record struct` for stack-allocated value types.
|
|
21
|
+
- **Pattern Matching**: `is` patterns, `switch` expressions, property/positional patterns.
|
|
22
|
+
- **Async/Await**: Always use `CancellationToken`. `ValueTask` for hot paths. `ConfigureAwait(false)` in libraries.
|
|
23
|
+
- **LINQ**: Prefer method syntax. Avoid multiple enumerations (`ToList()` once). Use `AsNoTracking()` for read-only EF queries.
|
|
24
|
+
- **Generics**: Constraints (`where T : class, new()`), covariance (`out T`), contravariance (`in T`).
|
|
25
|
+
- **Spans**: `Span<T>`, `ReadOnlySpan<T>` for zero-allocation slicing.
|
|
26
|
+
- **Primary Constructors**: C# 12+ `class Foo(int x)` for concise DI.
|
|
27
|
+
- **Collection Expressions**: C# 12+ `[1, 2, 3]` syntax.
|
|
28
|
+
- **Raw String Literals**: `"""multi-line"""` for SQL, JSON templates.
|
|
29
|
+
|
|
30
|
+
## Anti-Patterns
|
|
31
|
+
|
|
32
|
+
- **No `async void`**: Use `async Task`. Exception: event handlers.
|
|
33
|
+
- **No `Task.Result`/`.Wait()`**: Deadlock risk. Always `await`.
|
|
34
|
+
- **No `DateTime.Now`**: Use `DateTimeOffset.UtcNow` for timezone safety.
|
|
35
|
+
- **No string concat in loops**: Use `StringBuilder` or `string.Join`.
|
|
36
|
+
- **No `!` abuse**: Prefer null checks or `??` over null-forgiving.
|
|
37
|
+
|
|
38
|
+
## Code
|
|
39
|
+
|
|
40
|
+
```csharp
|
|
41
|
+
// Record with primary constructor
|
|
42
|
+
public record UserDto(string Name, string Email);
|
|
43
|
+
|
|
44
|
+
// Pattern matching with switch expression
|
|
45
|
+
string GetStatus(Order order) => order switch
|
|
46
|
+
{
|
|
47
|
+
{ Status: OrderStatus.Pending } => "Waiting",
|
|
48
|
+
{ Status: OrderStatus.Shipped, TrackingNumber: not null } => "In Transit",
|
|
49
|
+
{ IsCancelled: true } => "Cancelled",
|
|
50
|
+
_ => "Unknown"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Async with cancellation token
|
|
54
|
+
async Task<User?> GetUserAsync(int id, CancellationToken ct = default)
|
|
55
|
+
{
|
|
56
|
+
return await _db.Users
|
|
57
|
+
.AsNoTracking()
|
|
58
|
+
.FirstOrDefaultAsync(u => u.Id == id, ct);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Span for zero-allocation parsing
|
|
62
|
+
ReadOnlySpan<char> GetFirstWord(ReadOnlySpan<char> text)
|
|
63
|
+
{
|
|
64
|
+
int idx = text.IndexOf(' ');
|
|
65
|
+
return idx < 0 ? text : text[..idx];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Primary constructor (C# 12)
|
|
69
|
+
public class UserService(IUserRepository repo, ILogger<UserService> logger)
|
|
70
|
+
{
|
|
71
|
+
public async Task<User?> GetAsync(int id) => await repo.GetByIdAsync(id);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Reference & Examples
|
|
76
|
+
|
|
77
|
+
For advanced patterns, spans, and nullable annotations:
|
|
78
|
+
See [references/REFERENCE.md](references/REFERENCE.md).
|
|
79
|
+
|
|
80
|
+
## Related Topics
|
|
81
|
+
|
|
82
|
+
best-practices | security | tooling
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# C# Language Patterns Reference
|
|
2
|
+
|
|
3
|
+
Advanced type patterns, spans, and modern C# features.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Pattern Matching**](pattern-matching.md) - Switch expressions, property patterns.
|
|
8
|
+
- [**Nullable Annotations**](nullable-annotations.md) - `[NotNull]`, `[MaybeNull]`, flow analysis.
|
|
9
|
+
- [**Spans & Memory**](spans-memory.md) - Zero-allocation patterns.
|
|
10
|
+
|
|
11
|
+
## Advanced Pattern Matching
|
|
12
|
+
|
|
13
|
+
```csharp
|
|
14
|
+
// List patterns (C# 11+)
|
|
15
|
+
int[] numbers = [1, 2, 3, 4, 5];
|
|
16
|
+
var result = numbers switch
|
|
17
|
+
{
|
|
18
|
+
[1, 2, ..] => "Starts with 1, 2",
|
|
19
|
+
[_, _, 3, ..] => "Third element is 3",
|
|
20
|
+
{ Length: > 10 } => "Long array",
|
|
21
|
+
[] => "Empty",
|
|
22
|
+
_ => "Other"
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Property patterns with nested matching
|
|
26
|
+
string Describe(Person person) => person switch
|
|
27
|
+
{
|
|
28
|
+
{ Name: "Admin", Role: { Permissions: { IsAdmin: true } } } => "Full access",
|
|
29
|
+
{ Age: >= 18, IsVerified: true } => "Verified adult",
|
|
30
|
+
{ Age: < 18 } => "Minor",
|
|
31
|
+
_ => "Standard user"
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Relational patterns
|
|
35
|
+
string GetTaxBracket(decimal income) => income switch
|
|
36
|
+
{
|
|
37
|
+
<= 10_000m => "0%",
|
|
38
|
+
<= 50_000m => "10%",
|
|
39
|
+
<= 100_000m => "20%",
|
|
40
|
+
_ => "30%"
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Nullable Reference Types
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
// Nullable annotations
|
|
48
|
+
public class UserService
|
|
49
|
+
{
|
|
50
|
+
// Parameter never null after validation
|
|
51
|
+
public User GetUser([NotNull] string? id)
|
|
52
|
+
{
|
|
53
|
+
ArgumentNullException.ThrowIfNull(id);
|
|
54
|
+
return _repo.Find(id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Return may be null
|
|
58
|
+
[return: MaybeNull]
|
|
59
|
+
public T Find<T>(int id) where T : class
|
|
60
|
+
{
|
|
61
|
+
return _context.Set<T>().Find(id);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Output parameter set if returns true
|
|
65
|
+
public bool TryGet(int id, [NotNullWhen(true)] out User? user)
|
|
66
|
+
{
|
|
67
|
+
user = _repo.Find(id);
|
|
68
|
+
return user is not null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Null-coalescing patterns
|
|
73
|
+
string name = user?.Name ?? "Anonymous";
|
|
74
|
+
int length = text?.Length ?? 0;
|
|
75
|
+
|
|
76
|
+
// Null-conditional with assignment
|
|
77
|
+
user?.Settings?.Theme = "dark"; // No-op if null
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Span and Memory Patterns
|
|
81
|
+
|
|
82
|
+
```csharp
|
|
83
|
+
// Zero-allocation string processing
|
|
84
|
+
public static int CountWords(ReadOnlySpan<char> text)
|
|
85
|
+
{
|
|
86
|
+
if (text.IsEmpty) return 0;
|
|
87
|
+
|
|
88
|
+
int count = 0;
|
|
89
|
+
bool inWord = false;
|
|
90
|
+
|
|
91
|
+
foreach (char c in text)
|
|
92
|
+
{
|
|
93
|
+
if (char.IsWhiteSpace(c))
|
|
94
|
+
{
|
|
95
|
+
inWord = false;
|
|
96
|
+
}
|
|
97
|
+
else if (!inWord)
|
|
98
|
+
{
|
|
99
|
+
inWord = true;
|
|
100
|
+
count++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Stackalloc for small buffers
|
|
107
|
+
public static string FormatId(int id)
|
|
108
|
+
{
|
|
109
|
+
Span<char> buffer = stackalloc char[16];
|
|
110
|
+
id.TryFormat(buffer, out int written);
|
|
111
|
+
return new string(buffer[..written]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Memory<T> for async scenarios
|
|
115
|
+
public async Task ProcessAsync(Memory<byte> buffer)
|
|
116
|
+
{
|
|
117
|
+
await _stream.ReadAsync(buffer);
|
|
118
|
+
// Process buffer...
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Generics with Constraints
|
|
123
|
+
|
|
124
|
+
```csharp
|
|
125
|
+
// Multiple constraints
|
|
126
|
+
public class Repository<T> where T : class, IEntity, new()
|
|
127
|
+
{
|
|
128
|
+
public T Create() => new T();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Covariance (out) - can return derived types
|
|
132
|
+
public interface IReadOnlyRepository<out T>
|
|
133
|
+
{
|
|
134
|
+
T? GetById(int id);
|
|
135
|
+
IEnumerable<T> GetAll();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Contravariance (in) - can accept base types
|
|
139
|
+
public interface IComparer<in T>
|
|
140
|
+
{
|
|
141
|
+
int Compare(T x, T y);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Static abstract members (C# 11+)
|
|
145
|
+
public interface IParsable<TSelf> where TSelf : IParsable<TSelf>
|
|
146
|
+
{
|
|
147
|
+
static abstract TSelf Parse(string s);
|
|
148
|
+
static abstract bool TryParse(string? s, out TSelf result);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## C# 12+ Features
|
|
153
|
+
|
|
154
|
+
```csharp
|
|
155
|
+
// Collection expressions
|
|
156
|
+
int[] numbers = [1, 2, 3, 4, 5];
|
|
157
|
+
List<string> names = ["Alice", "Bob"];
|
|
158
|
+
Span<int> span = [1, 2, 3];
|
|
159
|
+
|
|
160
|
+
// Spread operator
|
|
161
|
+
int[] combined = [..numbers, 6, 7, ..otherNumbers];
|
|
162
|
+
|
|
163
|
+
// Primary constructors for classes
|
|
164
|
+
public class OrderService(IOrderRepository repo, ILogger<OrderService> logger)
|
|
165
|
+
{
|
|
166
|
+
public async Task<Order?> GetAsync(int id)
|
|
167
|
+
{
|
|
168
|
+
logger.LogDebug("Fetching order {OrderId}", id);
|
|
169
|
+
return await repo.GetByIdAsync(id);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Alias any type
|
|
174
|
+
using Point = (int X, int Y);
|
|
175
|
+
using UserId = System.Int32;
|
|
176
|
+
|
|
177
|
+
// Default lambda parameters
|
|
178
|
+
var greet = (string name = "World") => $"Hello, {name}!";
|
|
179
|
+
|
|
180
|
+
// Inline arrays (for high-performance scenarios)
|
|
181
|
+
[InlineArray(16)]
|
|
182
|
+
public struct Buffer16<T>
|
|
183
|
+
{
|
|
184
|
+
private T _element0;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Async Patterns
|
|
189
|
+
|
|
190
|
+
```csharp
|
|
191
|
+
// ValueTask for hot paths
|
|
192
|
+
public ValueTask<int> GetCachedCountAsync()
|
|
193
|
+
{
|
|
194
|
+
if (_cache.TryGetValue("count", out int count))
|
|
195
|
+
return ValueTask.FromResult(count);
|
|
196
|
+
|
|
197
|
+
return new ValueTask<int>(LoadCountAsync());
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// IAsyncEnumerable for streaming
|
|
201
|
+
public async IAsyncEnumerable<User> GetUsersAsync(
|
|
202
|
+
[EnumeratorCancellation] CancellationToken ct = default)
|
|
203
|
+
{
|
|
204
|
+
await foreach (var user in _db.Users.AsAsyncEnumerable().WithCancellation(ct))
|
|
205
|
+
{
|
|
206
|
+
yield return user;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Parallel async with SemaphoreSlim
|
|
211
|
+
public async Task ProcessAllAsync(IEnumerable<int> ids, int maxConcurrency = 10)
|
|
212
|
+
{
|
|
213
|
+
using var semaphore = new SemaphoreSlim(maxConcurrency);
|
|
214
|
+
var tasks = ids.Select(async id =>
|
|
215
|
+
{
|
|
216
|
+
await semaphore.WaitAsync();
|
|
217
|
+
try { await ProcessAsync(id); }
|
|
218
|
+
finally { semaphore.Release(); }
|
|
219
|
+
});
|
|
220
|
+
await Task.WhenAll(tasks);
|
|
221
|
+
}
|
|
222
|
+
```
|