Queries
Fluent builders for finding types, methods, properties, fields, constructors, events, and parameters.
See also: Projections | Emit | Extensions | Roslyn Toolkit README
Overview
Query builders let you compose chainable filters on Roslyn symbols:
- Immutable — each method returns a new instance
- Lazy — filters are applied when you call
GetAll(), First(), etc. - Safe — materialization returns
ValidSymbol<T> wrappers with guaranteed non-null access
// Find all public async methods returning Task<T>
var methods = typeSymbol.QueryMethods()
.ThatArePublic()
.ThatAreAsync()
.ReturningGenericTask()
.GetAll();
// Project results directly to your model
var models = TypeQuery.From(compilation)
.ThatAreClasses()
.WithAttribute("Entity")
.Select(t => new EntityModel(t.Name, t.Namespace));
TypeQuery
Find types in a compilation or namespace.
// From a compilation
var types = TypeQuery.From(compilation)
.ThatArePublic()
.ThatAreClasses()
.WithAttribute("MyAttribute")
.GetAll();
// From a namespace symbol
var types = TypeQuery.From(namespaceSymbol)
.ThatAreInterfaces()
.InNamespaceStartingWith("MyApp.Domain")
.GetAll();
// Using extension method
var types = compilation.QueryTypes()
.ThatAreRecords()
.GetAll();
Factory Methods
| Method | Description |
From(Compilation) | Query all types in the compilation |
From(INamespaceSymbol) | Query types from a specific namespace |
Accessibility Filters
| Method | Description |
ThatArePublic() | Public types |
ThatAreNotPublic() | Non-public types |
ThatAreInternal() | Internal types |
ThatAreNotInternal() | Non-internal types |
ThatArePrivate() | Private types (nested only) |
ThatAreNotPrivate() | Non-private types |
ThatAreProtected() | Protected types (nested only) |
ThatAreNotProtected() | Non-protected types |
Type Kind Filters
| Method | Description |
ThatAreClasses() | Class types |
ThatAreNotClasses() | Non-class types |
ThatAreInterfaces() | Interface types |
ThatAreNotInterfaces() | Non-interface types |
ThatAreStructs() | Struct types |
ThatAreNotStructs() | Non-struct types |
ThatAreEnums() | Enum types |
ThatAreNotEnums() | Non-enum types |
ThatAreDelegates() | Delegate types |
ThatAreNotDelegates() | Non-delegate types |
ThatAreRecords() | Record types (class or struct) |
ThatAreNotRecords() | Non-record types |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static types |
ThatAreNotStatic() | Non-static types |
ThatAreAbstract() | Abstract types |
ThatAreNotAbstract() | Non-abstract types |
ThatAreSealed() | Sealed types |
ThatAreNotSealed() | Non-sealed types |
ThatAreGeneric() | Generic types |
ThatAreNotGeneric() | Non-generic types |
ThatArePartial() | Partial types |
ThatAreNotPartial() | Non-partial types |
ThatAreRefStructs() | Ref struct types |
ThatAreNotRefStructs() | Non-ref struct types |
ThatAreReadOnlyStructs() | Readonly struct types |
ThatAreNotReadOnlyStructs() | Non-readonly struct types |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNameStartingWith(string) | Name starts with prefix |
WithNameContaining(string) | Name contains substring |
WithNameEndingWith(string) | Name ends with suffix |
Inheritance Filters
| Method | Description |
InheritingFrom(INamedTypeSymbol) | Types inheriting from base type |
ImplementingInterface(INamedTypeSymbol) | Types implementing interface |
ImplementingInterface(string) | Types implementing interface by name |
Namespace Filters
| Method | Description |
InNamespace(string) | Exact namespace match |
InNamespaceStartingWith(string) | Namespace starts with prefix |
IncludeNestedNamespaces() | Include types in nested namespaces |
Attribute Filters
| Method | Description |
WithAttribute(string) | Types with attribute (with or without "Attribute" suffix) |
Materialization
| Method | Returns | Description |
GetAll() | ImmutableArray<ValidSymbol<INamedTypeSymbol>> | All matches as validated wrappers |
GetAllSymbols() | ImmutableArray<INamedTypeSymbol> | Raw symbols |
Select<T>(Func) | ImmutableArray<T> | Project each to a model |
SelectMany<T>(Func) | ImmutableArray<T> | Project and flatten |
FirstOrDefault() | OptionalSymbol<INamedTypeSymbol> | First match or empty |
First() | ValidSymbol<INamedTypeSymbol> | First match (throws if none) |
Any() | bool | True if any match |
Count() | int | Count of matches |
MethodQuery
Find methods on a type.
// Static factory
var methods = MethodQuery.From(typeSymbol)
.ThatAreAsync()
.ThatArePublic()
.ReturningTask()
.GetAll();
// Extension method (preferred)
var handlers = typeSymbol.QueryMethods()
.WithNameEndingWith("Handler")
.WithParameterCount(1)
.GetAll();
Factory Methods
| Method | Description |
From(ITypeSymbol) | Query methods on a type |
Accessibility Filters
| Method | Description |
ThatArePublic() | Public methods |
ThatAreNotPublic() | Non-public methods |
ThatArePrivate() | Private methods |
ThatAreNotPrivate() | Non-private methods |
ThatAreProtected() | Protected methods |
ThatAreNotProtected() | Non-protected methods |
ThatAreInternal() | Internal methods |
ThatAreNotInternal() | Non-internal methods |
ThatAreProtectedOrInternal() | Protected internal methods |
ThatAreNotProtectedOrInternal() | Non-protected internal methods |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static methods |
ThatAreInstance() | Instance methods |
ThatAreAsync() | Async methods |
ThatAreNotAsync() | Non-async methods |
ThatAreGeneric() | Generic methods |
ThatAreNotGeneric() | Non-generic methods |
ThatAreVirtual() | Virtual methods |
ThatAreNotVirtual() | Non-virtual methods |
ThatAreAbstract() | Abstract methods |
ThatAreNotAbstract() | Non-abstract methods |
ThatAreOverrides() | Override methods |
ThatAreNotOverrides() | Non-override methods |
ThatAreSealed() | Sealed methods |
ThatAreNotSealed() | Non-sealed methods |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNameStartingWith(string) | Name starts with prefix |
WithNameEndingWith(string) | Name ends with suffix |
WithNameContaining(string) | Name contains substring |
Parameter Filters
| Method | Description |
WithParameterCount(int) | Exact parameter count |
WithNoParameters() | No parameters |
WithParameters() | At least one parameter |
WithFirstParameterOfType(string) | First parameter matches type name |
WithParameters(Func<ImmutableArray<IParameterSymbol>, bool>) | Custom parameter predicate |
Return Type Filters
| Method | Description |
WithReturnType(string) | Return type name match |
WithReturnType(Func<ITypeSymbol, bool>) | Custom return type predicate |
ReturningVoid() | Returns void |
ReturningTask() | Returns Task or ValueTask |
ReturningValueTask() | Returns ValueTask |
ReturningGenericTask() | Returns Task or ValueTask |
Attribute Filters
| Method | Description |
WithAttribute<TAttribute>() | Has attribute type |
WithAttribute(string) | Has attribute by name |
WithoutAttribute<TAttribute>() | Lacks attribute type |
Materialization
Same as TypeQuery: GetAll(), GetAllSymbols(), Select<T>(), SelectMany<T>(), FirstOrDefault(), First(), Any(), Count()
PropertyQuery
Find properties on a type.
var requiredProps = typeSymbol.QueryProperties()
.ThatAreRequired()
.ThatArePublic()
.GetAll();
var readOnlyProps = typeSymbol.QueryProperties()
.ThatAreReadOnly()
.WithoutAttribute<ObsoleteAttribute>()
.GetAll();
Accessibility Filters
| Method | Description |
ThatArePublic() | Public properties |
ThatAreNotPublic() | Non-public properties |
ThatArePrivate() | Private properties |
ThatAreNotPrivate() | Non-private properties |
ThatAreProtected() | Protected properties |
ThatAreNotProtected() | Non-protected properties |
ThatAreInternal() | Internal properties |
ThatAreNotInternal() | Non-internal properties |
ThatAreProtectedOrInternal() | Protected internal properties |
ThatAreNotProtectedOrInternal() | Non-protected internal properties |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static properties |
ThatAreInstance() | Instance properties |
ThatAreVirtual() | Virtual properties |
ThatAreNotVirtual() | Non-virtual properties |
ThatAreAbstract() | Abstract properties |
ThatAreNotAbstract() | Non-abstract properties |
ThatAreOverride() | Override properties |
ThatAreNotOverride() | Non-override properties |
ThatAreSealed() | Sealed properties |
ThatAreNotSealed() | Non-sealed properties |
ThatAreReadOnly() | Read-only (no setter) |
ThatAreWriteOnly() | Write-only (no getter) |
ThatAreReadWrite() | Has getter and setter |
WithInitOnlySetter() | Init-only setter |
ThatAreRequired() | Required properties |
ThatAreNotRequired() | Non-required properties |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNameStartingWith(string) | Name starts with prefix |
WithNameContaining(string) | Name contains substring |
WithNameEndingWith(string) | Name ends with suffix |
Type Filters
| Method | Description |
OfType(ITypeSymbol) | Exact type match |
OfTypeName(string) | Type name match |
OfType(Func<ITypeSymbol, bool>) | Custom type predicate |
Attribute Filters
| Method | Description |
WithAttribute<TAttribute>() | Has attribute type |
WithAttribute(string) | Has attribute by name |
WithoutAttribute<TAttribute>() | Lacks attribute type |
FieldQuery
Find fields on a type.
var constants = typeSymbol.QueryFields()
.ThatAreConst()
.ThatArePublic()
.GetAll();
var injectableFields = typeSymbol.QueryFields()
.WithAttribute("Inject")
.ThatArePrivate()
.GetAll();
Accessibility Filters
| Method | Description |
ThatArePublic() | Public fields |
ThatAreNotPublic() | Non-public fields |
ThatArePrivate() | Private fields |
ThatAreNotPrivate() | Non-private fields |
ThatAreProtected() | Protected fields |
ThatAreNotProtected() | Non-protected fields |
ThatAreInternal() | Internal fields |
ThatAreNotInternal() | Non-internal fields |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static fields |
ThatAreInstance() | Instance fields |
ThatAreReadOnly() | Readonly fields |
ThatAreNotReadOnly() | Non-readonly fields |
ThatAreConst() | Const fields |
ThatAreNotConst() | Non-const fields |
ThatAreVolatile() | Volatile fields |
ThatAreNotVolatile() | Non-volatile fields |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNamePrefix(string) | Name starts with prefix |
WithNameSuffix(string) | Name ends with suffix |
WithNameMatching(Func<string, bool>) | Custom name predicate |
Type Filters
| Method | Description |
WithType<T>() | Fields of type T |
WithType(string) | Fields with type name |
ThatAreGenericType() | Fields with generic types |
ThatAreNotGenericType() | Fields without generic types |
ThatAreNullable() | Fields with nullable annotation |
ThatAreNotNullable() | Fields without nullable annotation |
Attribute Filters
| Method | Description |
WithAttribute<TAttribute>() | Has attribute type |
WithAttribute(string) | Has attribute by name |
WithoutAttribute<TAttribute>() | Lacks attribute type |
ConstructorQuery
Find constructors on a type.
var publicCtors = typeSymbol.QueryConstructors()
.ThatArePublic()
.ThatAreInstance()
.GetAll();
var parameterless = typeSymbol.QueryConstructors()
.WithNoParameters()
.FirstOrDefault();
Accessibility Filters
| Method | Description |
ThatArePublic() | Public constructors |
ThatAreNotPublic() | Non-public constructors |
ThatArePrivate() | Private constructors |
ThatAreNotPrivate() | Non-private constructors |
ThatAreProtected() | Protected constructors |
ThatAreNotProtected() | Non-protected constructors |
ThatAreInternal() | Internal constructors |
ThatAreNotInternal() | Non-internal constructors |
ThatAreProtectedOrInternal() | Protected internal constructors |
ThatAreNotProtectedOrInternal() | Non-protected internal constructors |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static constructors |
ThatAreInstance() | Instance constructors |
Parameter Filters
| Method | Description |
WithParameterCount(int) | Exact parameter count |
WithNoParameters() | Parameterless constructor |
WithAtLeastParameters(int) | Minimum parameter count |
WithFirstParameterOfType(ITypeSymbol) | First parameter matches type |
WithParameter(Func<IParameterSymbol, bool>) | Any parameter matches predicate |
WhereAllParameters(Func<IParameterSymbol, bool>) | All parameters match predicate |
Attribute Filters
| Method | Description |
WithAttribute(string) | Has attribute by name |
EventQuery
Find events on a type.
var publicEvents = typeSymbol.QueryEvents()
.ThatArePublic()
.WithType("EventHandler")
.GetAll();
Accessibility Filters
| Method | Description |
ThatArePublic() | Public events |
ThatAreNotPublic() | Non-public events |
ThatArePrivate() | Private events |
ThatAreNotPrivate() | Non-private events |
ThatAreProtected() | Protected events |
ThatAreNotProtected() | Non-protected events |
ThatAreInternal() | Internal events |
ThatAreNotInternal() | Non-internal events |
Modifier Filters
| Method | Description |
ThatAreStatic() | Static events |
ThatAreInstance() | Instance events |
ThatAreAbstract() | Abstract events |
ThatAreNotAbstract() | Non-abstract events |
ThatAreVirtual() | Virtual events |
ThatAreNotVirtual() | Non-virtual events |
ThatAreSealed() | Sealed events |
ThatAreNotSealed() | Non-sealed events |
ThatAreOverride() | Override events |
ThatAreNotOverride() | Non-override events |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNamePrefix(string) | Name starts with prefix |
WithNameSuffix(string) | Name ends with suffix |
WithNameMatching(Func<string, bool>) | Custom name predicate |
Type Filters
| Method | Description |
WithType<T>() | Events of type T |
WithType(string) | Events with type name |
Attribute Filters
| Method | Description |
WithAttribute<TAttribute>() | Has attribute type |
WithAttribute(string) | Has attribute by name |
WithoutAttribute<TAttribute>() | Lacks attribute type |
ParameterQuery
Find parameters on a method.
var optionalParams = ParameterQuery.From(methodSymbol)
.ThatAreOptional()
.GetAll();
var refParams = methodSymbol.QueryParameters()
.ThatAreRef()
.GetAll();
Factory Methods
| Method | Description |
From(IMethodSymbol) | Query parameters on a method |
Modifier Filters
| Method | Description |
ThatAreRef() | Ref parameters |
ThatAreNotRef() | Non-ref parameters |
ThatAreOut() | Out parameters |
ThatAreNotOut() | Non-out parameters |
ThatAreIn() | In parameters |
ThatAreNotIn() | Non-in parameters |
ThatAreParams() | Params array parameters |
ThatAreNotParams() | Non-params parameters |
ThatAreOptional() | Optional parameters (with defaults) |
ThatAreRequired() | Required parameters |
ThatAreThis() | Extension method 'this' parameter |
ThatAreNotThis() | Non-this parameters |
ThatAreDiscards() | Discard parameters (named _) |
ThatAreNotDiscards() | Non-discard parameters |
Name Filters
| Method | Description |
WithName(string) | Exact name match |
WithNamePrefix(string) | Name starts with prefix |
WithNameSuffix(string) | Name ends with suffix |
WithNameMatching(Func<string, bool>) | Custom name predicate |
Type Filters
| Method | Description |
WithType<T>() | Parameters of type T |
WithType(string) | Parameters with type name |
ThatAreGenericType() | Parameters with generic types |
ThatAreNotGenericType() | Parameters without generic types |
ThatAreNullable() | Parameters with nullable annotation |
ThatAreNotNullable() | Parameters without nullable annotation |
Position Filters
| Method | Description |
AtPosition(int) | Parameter at specific index |
ThatAreFirst() | First parameter |
ThatAreLast() | Last parameter |
Attribute Filters
| Method | Description |
WithAttribute<TAttribute>() | Has attribute type |
WithAttribute(string) | Has attribute by name |
WithoutAttribute<TAttribute>() | Lacks attribute type |
Custom Filters
All query builders support Where() for custom predicates:
var special = TypeQuery.From(compilation)
.Where(t => t.GetMembers().Length > 10)
.Where(t => t.ContainingNamespace?.Name == "Domain")
.GetAll();
Common Patterns
Filter and Project
var models = TypeQuery.From(compilation)
.ThatAreClasses()
.WithAttribute("Entity")
.Select(type => new EntityModel
{
Name = type.Name,
Properties = type.Value.QueryProperties().ThatArePublic().GetAll()
});
Early Exit with FirstOrDefault
var handler = typeSymbol.QueryMethods()
.WithName("Handle")
.WithParameterCount(1)
.FirstOrDefault();
if (handler.IsNotValid(out var valid))
return; // No handler found
// Use valid.Name, valid.Value, etc.
Chaining Queries
var targetMethods = new HashSet<string>(
attribute.TargetType.QueryMethods()
.ThatArePublic()
.Select(m => m.Name)
);
License
RPL-1.5 (Reciprocal Public License) — Real reciprocity, no loopholes.
You can use this code, modify it, and share it freely. But when you deploy it — internally or externally, as a service or within your company — you share your improvements back under the same license.
Why? We believe if you benefit from this code, the community should benefit from your improvements. That's the deal we think is fair.
Personal research and experimentation? No obligations. Go learn, explore, and build.
See LICENSE for the full legal text.