Non-static classes should be instantiated or turned to static
A class whose constructors are never called is never instantiated and should be declared static.
Instantiation through reflection is not detected, so plug-in root classes instantiated via IoC frameworks can be false positives. Classes instantiated by ASP.NET infrastructure, view models and Entity Framework ModelSnapshot/DbContext/Migration classes are skipped. So are classes deriving from a third-party abstract class (an endpoint, a hosted service), and classes whose instance members are used by another type: a request DTO or a JSON response, created by a model binder or a serializer. Public classes are matched by default; for a framework whose clients instantiate them, uncomment !t.IsPublic.
Instantiation through reflection is not detected, so plug-in root classes instantiated via IoC frameworks can be false positives. Classes instantiated by ASP.NET infrastructure, view models and Entity Framework ModelSnapshot/DbContext/Migration classes are skipped. So are classes deriving from a third-party abstract class (an endpoint, a hosted service), and classes whose instance members are used by another type: a request DTO or a JSON response, created by a model binder or a serializer. Public classes are matched by default; for a framework whose clients instantiate them, uncomment !t.IsPublic.
How to fix
Investigate why the class is never instantiated. If it hosts only static methods, declare it static. If it is instantiated via reflection or by client code, adapt this rule to avoid these matches.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Non-static classes should be instantiated or turned to static</Name>
// <Id>ND1207:NonStaticClassesShouldBeInstantiatedOrTurnedToStatic</Id>
warnif count > 0
from t in JustMyCode.Types
where t.IsClass &&
//!t.IsPublic && // if you are developing a framework,
// you might not want to match public classes
!t.IsStatic &&
!t.IsAbstract &&
!t.IsDelegate &&
!t.IsAttributeClass && // Attributes class are never seen as instantiated
// Don't suggest to turn to static, classes that implement interfaces
t.InterfacesImplemented.Count() == 0 &&
// Find the first constructor of t called
// match t if none of its constructors is called.
t.Constructors.FirstOrDefault(ctor => ctor.NbMethodsCallingMe > 0) == null &&
// Don't warn on Program classes generated by designers
t.SimpleName != "Program" &&
// Types instantiated through remoting infrastructure
!t.DeriveFrom("System.MarshalByRefObject".AllowNoMatch()) &&
// JSON, XML and binary serialized types might not be seen as instantiated.
!t.IsUsing("Newtonsoft.Json".MatchNamespace().AllowNoMatch()) &&
!t.IsUsing("System.Text.Json".MatchNamespace().AllowNoMatch()) &&
!t.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
!t.IsUsing("System.Xml.Serialization.XmlElementAttribute".AllowNoMatch()) &&
!t.IsUsing("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
!t.HasAttribute ("System.SerializableAttribute".AllowNoMatch()) &&
// Serialized type might never be seen as instantiated.
!t.HasAttribute("System.Runtime.Serialization.DataContractAttribute".AllowNoMatch()) &&
!t.IsUsing("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch()) &&
// ASP.NET Core ViewModel and Repository
!t.SimpleName.EndsWithAny("Model","Repository") &&
!t.IsUsing("System.ComponentModel.DataAnnotations".AllowNoMatch().MatchNamespace()) &&
// ASP.NET Classes that are instantiated by the ASP.NET infrastructure.
!t.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWithAny("System.Web", "Microsoft.AspNetCore")) &&
!(t.Constructors.Count() == 1 && t.Constructors.Single().Name.Contains("(IHostingEnvironment)")) &&
// A class deriving from a third-party abstract class is a framework extension point (an endpoint,
// a hosted service, a hub...): the framework instantiates it, and it cannot be declared static.
!t.BaseClasses.Any(bc => bc.IsThirdParty && bc.IsAbstract) &&
// A class whose instance members are used by another type has instances at runtime, created outside
// the analyzed code: by a model binder, a JSON serializer or reflection (a request DTO, a JSON response).
!t.InstanceMethods.Any(m => m.MethodsCallingMe.Any(c => c.ParentType != t)) &&
!t.InstanceFields.Any(f => f.MethodsUsingMe.Any(c => c.ParentType != t)) &&
// Entity Framework ModelSnapshot and DbContext and Migration
!t.DeriveFrom("Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch()) &&
!t.DeriveFrom("Microsoft.EntityFrameworkCore.DbContext".AllowNoMatch()) &&
!t.DeriveFrom("Microsoft.EntityFrameworkCore.Migrations.Migration".AllowNoMatch()) &&
// ASP.NET Core Tag Helpers
!t.HasAttribute("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute".AllowNoMatch()) &&
!t.DeriveFrom("HtmlTags.HtmlTagTagHelper".AllowNoMatch()) &&
// UWP Pages
!t.InstanceMethods.WithName("GetBindingConnector(Int32,Object)").Any() &&
// Validtor classes might not be instantiated
!t.SimpleName.EndsWith("Validator") &&
// Don't warn about classes instantiated by Dependency Injection frameworks
!t.TypesUsingMe.Any(t1 => t1.TypesUsed.ParentNamespaces().Any(n => n.Name.StartsWithAny(
"Microsoft.Extensions.DependencyInjection",
"Autofac", "Microsoft.Practices.Unity", "Ninject",
"StructureMap", "SimpleInjector", "Castle.Windsor",
"LightInject", "Spring", "Lamar", "AutoMapper"
))) &&
!t.BaseClasses.Any(bc => bc.FullName.StartsWith("AutoMapper")) &&
// Don't warn if the type is used by some types using some third-party Json related types.
// The type is potentially instantiated by a Json serializer like the GetFromJsonAsync() extension methods.
!t.TypesUsingMe.SelectMany(t1 => t1.TypesUsed)
.Where(t1 => t1.IsThirdParty && t1.SimpleName.Contains("Json")).Any() &&
// Classes that derive from Unity classes are instantiated implicitly by the Unity engine
!t.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWithAny("UnityEngine","UnityEditor")) &&
// Don't match marker classes
!(t.IsSealed && t.Members.Count() == 1 &&
t.Members.Single().IsMethod &&
t.Members.Single().AsMethod.IsConstructor &&
t.Members.Single().AsMethod.NbParameters == 0)
select new {
t,
t.Visibility,
Debt = 2.ToMinutes().ToDebt(),
Severity = Severity.Medium
}
// Notice that classes only instantiated through reflection,
// like plug-in root classes are matched by this rules.
//<Expl>
// The *{0}* is not instantiated in the context of the analyzed code.
// Should it be declared as a *static class* or is it a potential candidate for removal?
//</Expl>
//<Desc>
// A class whose constructors are never called is never instantiated and
// should be declared *static*.
//
// Instantiation through reflection is not detected, so plug-in root classes
// instantiated via *IoC frameworks* can be *false positives*. Classes
// instantiated by ASP.NET infrastructure, view models and Entity Framework
// ModelSnapshot/DbContext/Migration classes are skipped. So are classes
// deriving from a third-party abstract class (an endpoint, a hosted service),
// and classes whose instance members are used by another type: a request DTO
// or a JSON response, created by a model binder or a serializer. *Public*
// classes are matched by default; for a framework whose clients instantiate
// them, uncomment *!t.IsPublic*.
//</Desc>
//<HowToFix>
// Investigate why the class is never instantiated. If it hosts only static
// methods, declare it *static*. If it is instantiated via reflection or by
// client code, adapt this rule to avoid these matches.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Object Oriented Design: all 14 items
- Avoid interfaces too big ND1200
- Base class should not use derivatives ND1201
- Class shouldn't be too deep in inheritance tree ND1202
- Class with no descendant should be sealed if possible ND1203
- Overrides of Method() should call base.Method() ND1204
- Do not hide base class methods ND1205
- A stateless class or structure might be turned into a static type ND1206
- Non-static classes should be instantiated or turned to static ND1207
- Methods should be declared static if possible ND1208
- Constructor should not call a virtual method ND1209
- Avoid the Singleton pattern ND1210
- Don't assign static fields from instance methods ND1211
- Avoid empty interfaces ND1212
- Avoid types initialization cycles ND1213