README.md

April 11, 2026 ยท View on GitHub

Nuget Downloads Visual Studio Marketplace Downloads

Demonstration of an analyzer which removes unnecessary IEnumerable materializations

Quickstart

Install it through the command line:

Install-Package SharpSource

or add a reference yourself:

<ItemGroup>
    <PackageReference Include="SharpSource" Version="1.33.1" PrivateAssets="All" />
</ItemGroup>

If you would like to install it as an extension instead, download it from the marketplace.


This repo houses a collection of analyzers that aim to make some language features and framework types easier to work with. It does this by highlighting when you might be using something incorrectly in a way that would result in suboptimal performance, runtime exceptions or general unintended behaviour.

In other words, this repo only contains analyzers for patterns that have a concrete potential to turn into a defect ticket. It is not intended to help with general housekeeping tasks like formatting your code or providing productivity helpers.

Interested in contributing? Take a look at the guidelines!


Detailed explanations of each analyzer can be found in the documentation: https://github.com/Vannevelj/SharpSource/tree/master/docs

CodeNameDescription
SS001AsyncMethodWithVoidReturnTypeAsync methods should return Task instead of void to allow proper exception handling and awaiting.
SS002DateTimeNowUse DateTime.UtcNow instead of DateTime.Now to avoid timezone-related issues.
SS003DivideIntegerByIntegerDividing integers results in integer division; cast to floating-point if a decimal result is expected.
SS004ElementaryMethodsOfTypeInCollectionNotOverriddenTypes used as collection keys should override Equals and GetHashCode.
SS005EqualsAndGetHashcodeNotImplementedTogetherEquals and GetHashCode should always be overridden together.
SS006ThrowNullThrowing null will result in a NullReferenceException at runtime.
SS007FlagsEnumValuesAreNotPowersOfTwoFlags enum values should be powers of two to allow proper bitwise operations.
SS008GetHashCodeRefersToMutableMemberGetHashCode should not reference mutable members as this breaks hash-based collections.
SS009LoopedRandomInstantiationCreating Random instances in a loop can produce identical sequences; reuse a single instance.
SS010NewGuidUse Guid.NewGuid() instead of new Guid() to generate a unique identifier.
SS011OnPropertyChangedWithoutNameofOperatorUse nameof() instead of hardcoded property name strings in OnPropertyChanged.
SS012RecursiveOperatorOverloadOperator overloads calling themselves will cause infinite recursion.
SS013RethrowExceptionWithoutLosingStacktraceUse throw; instead of throw ex; to preserve the original stack trace.
SS014StringDotFormatWithDifferentAmountOfArgumentsThe number of format placeholders should match the number of arguments.
SS015StringPlaceholdersInWrongOrderFormat placeholders should be in sequential order starting from {0}.
SS017StructWithoutElementaryMethodsOverriddenStructs should override Equals, GetHashCode, and implement IEquatable<T> for performance.
SS018SwitchDoesNotHandleAllEnumOptionsSwitch statements on enums should handle all possible values.
SS019SwitchIsMissingDefaultLabelSwitch statements should have a default case to handle unexpected values.
SS020TestMethodWithoutPublicModifierTest methods must be public to be discovered by test runners.
SS021TestMethodWithoutTestAttributeMethods that look like tests should have a test attribute to be executed.
SS022ExceptionThrownFromImplicitOperatorImplicit operators should not throw exceptions as they are called invisibly.
SS023ExceptionThrownFromPropertyGetterProperty getters should not throw exceptions; consider using a method instead.
SS024ExceptionThrownFromStaticConstructorExceptions in static constructors cause TypeInitializationException and make the type unusable.
SS025ExceptionThrownFromFinallyBlockExceptions in finally blocks can mask original exceptions from try blocks.
SS026ExceptionThrownFromEqualityOperatorEquality operators should not throw exceptions; return false for invalid comparisons.
SS027ExceptionThrownFromDisposeDispose methods should not throw exceptions as they may be called during exception unwinding.
SS028ExceptionThrownFromFinalizerFinalizers should not throw exceptions as this will terminate the process.
SS029ExceptionThrownFromGetHashCodeGetHashCode should not throw exceptions; return a consistent value instead.
SS030ExceptionThrownFromEqualsEquals should not throw exceptions; return false for invalid comparisons.
SS032ThreadSleepInAsyncMethodUse await Task.Delay() instead of Thread.Sleep() in async methods to avoid blocking threads.
SS033AsyncOverloadsAvailableUse async overloads when available to avoid blocking the calling thread.
SS034AccessingTaskResultWithoutAwaitAccessing Task.Result without awaiting can cause deadlocks; use await instead.
SS035SynchronousTaskWaitUsing .Wait() or .Result on tasks can cause deadlocks; use await instead.
SS036ExplicitEnumValuesEnum members should have explicit values when the values are persisted or serialized.
SS037HttpClientInstantiatedDirectlyUse IHttpClientFactory instead of creating HttpClient directly to avoid socket exhaustion.
SS038HttpContextStoredInFieldHttpContext should not be stored in fields as it's request-scoped and may be invalid later.
SS039EnumWithoutDefaultValueEnums should have a member with value 0 to represent the default state.
SS040UnusedResultOnImmutableObjectMethods on immutable types return new instances; the result should not be discarded.
SS041UnnecessaryEnumerableMaterializationAvoid materializing enumerables (e.g., ToList()) when the result is immediately enumerated.
SS042InstanceFieldWithThreadStatic[ThreadStatic] only works on static fields; it has no effect on instance fields.
SS043MultipleFromBodyParametersWeb API actions can only have one [FromBody] parameter.
SS044AttributeMustSpecifyAttributeUsageCustom attributes should specify [AttributeUsage] to define valid targets.
SS045StaticInitializerAccessedBeforeInitializationStatic field initializers may access fields before they are initialized.
SS046UnboundedStackallocstackalloc without a size limit can cause stack overflow; consider using a maximum size.
SS047LinqTraversalBeforeFilterApply Where filters before Select projections to avoid unnecessary work.
SS048LockingOnDiscouragedObjectAvoid locking on this, typeof(), or strings as these can cause deadlocks.
SS049ComparingStringsWithoutStringComparisonString comparisons should specify a StringComparison to ensure correct behavior.
SS050ParameterAssignedInConstructorAssigning to a parameter instead of a field in a constructor is likely a mistake.
SS051LockingOnMutableReferenceLocking on a field that can be reassigned may cause race conditions.
SS052ThreadStaticWithInitializer[ThreadStatic] field initializers only run once; use lazy initialization instead.
SS053PointlessCollectionToStringCalling ToString() on collections returns the type name, not the contents.
SS054NewtonsoftMixedWithSystemTextJsonMixing Newtonsoft.Json and System.Text.Json attributes causes serialization issues.
SS055MultipleOrderByCallsMultiple OrderBy calls override each other; use ThenBy for secondary sorting.
SS056FormReadSynchronouslyReading form data synchronously blocks threads; use async methods instead.
SS057CollectionManipulatedDuringTraversalModifying a collection while iterating over it causes InvalidOperationException.
SS058StringConcatenatedInLoopUse StringBuilder instead of string concatenation in loops for better performance.
SS059DisposeAsyncDisposableTypes implementing IAsyncDisposable should be disposed with await using.
SS060ConcurrentDictionaryEmptyCheckUse IsEmpty instead of Count == 0 on ConcurrentDictionary for thread safety.
SS061ImmutableCollectionCreatedIncorrectlyUse builder methods or Create() instead of constructors for immutable collections.
SS062ActivityWasNotStoppedActivity instances must be stopped to ensure telemetry data is recorded.
SS063ValueTaskAwaitedMultipleTimesValueTask can only be awaited once; store the result or convert to Task if needed.
SS064UnnecessaryToStringOnSpanAvoid calling ToString() on spans when an overload accepting spans directly is available.
SS065LoggerMessageAttributeUse the [LoggerMessage] attribute for high-performance logging instead of extension methods.
SS066DisposableFieldIsNotDisposedDisposable fields owned by a type should be included in its disposal path to avoid resource leaks.
SS067RedisResponseNotHandledRedis responses must be checked for errors since these clients do not throw exceptions.
SS068TimeSpanConstructedWithTicksTimeSpan single-parameter constructor creates ticks (100ns), not seconds. Use TimeSpan.FromTickets() to avoid confusion.

Configuration

Is a particular rule not to your liking? There are many ways to adjust their severity and even disable them altogether. For an overview of some of the options, check out this document.