Attributes & Reflection

11 questions found

What is an attribute in C#, and how do you apply one to a class or method?

Beginner
An attribute is metadata attached to a code element (class, method, property, etc.) using square-bracket syntax placed directly above it — attributes don't affect runtime behavior on their own, but tools, frameworks, and your own reflection code can read them to alter behavior or generate documentation.
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }

[Serializable]
public class Product { public string Name { get; set; } = ""; }
Real-world example Marking a deprecated API method with [Obsolete] so callers get a compiler warning, or marking a class [Serializable] for legacy binary serialization.

Common follow-ups: Can you apply multiple attributes to the same code element?

Reflection

What is reflection, and what basic information can you retrieve from a Type object at runtime?

Beginner
Reflection lets you inspect metadata about types, methods, properties, and assemblies AT RUNTIME, even for types you don't have compile-time knowledge of — a Type object (obtained via typeof() or GetType()) exposes its name, properties, methods, constructors, and more.
Type type = typeof(string);
Console.WriteLine(type.Name);        // "String"
Console.WriteLine(type.Namespace);   // "System"
var methods = type.GetMethods();     // array of all public methods
Real-world example Building a generic object inspector/debugger tool that can display any object's properties without knowing its type ahead of time.

Common follow-ups: What's the difference between typeof(SomeType) and instance.GetType()?

Design Patterns in C#

How do you create a custom attribute class, and what does AttributeUsage control?

Intermediate
Define a class that inherits from System.Attribute (conventionally suffixed with "Attribute", though C# lets you omit the suffix when applying it); the [AttributeUsage] attribute on that class restricts WHICH code elements it can be applied to (class, method, property, etc.) and whether it can be applied multiple times to the same element.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RequiredAttribute : Attribute {
  public string ErrorMessage { get; set; } = "This field is required.";
}

public class User {
  [Required(ErrorMessage = "Name is mandatory")]
  public string Name { get; set; } = "";
}
Real-world example Building a lightweight custom validation attribute system for a domain model, similar in spirit to DataAnnotations.

Common follow-ups: What does 'AllowMultiple = true' allow you to do that's normally disallowed?

Dependency Injection & IoC Principles

How do you use reflection to read a custom attribute's values off a property at runtime?

Intermediate
Use GetCustomAttribute<T>() (or GetCustomAttributes for multiple) on a PropertyInfo, MethodInfo, or Type object to retrieve an instance of the applied attribute, then read its properties normally — this is the core mechanism behind validation libraries, serializers, and ORMs that inspect your classes' decorations.
var properties = typeof(User).GetProperties();
foreach (var prop in properties) {
  var required = prop.GetCustomAttribute<RequiredAttribute>();
  if (required != null) {
    Console.WriteLine($"{prop.Name}: {required.ErrorMessage}");
  }
}
Real-world example Building a simple validation engine that scans a model's properties for [Required] attributes and reports errors.

Common follow-ups: How would you check whether an attribute exists WITHOUT retrieving its full instance, for a quick presence check?

Design Patterns in C#

How do you dynamically create an instance of a type and invoke a method on it using reflection, when the type isn't known at compile time?

Intermediate
Activator.CreateInstance(type) constructs a new instance given a Type object (optionally with constructor arguments), and MethodInfo.Invoke(instance, args) calls a method on that instance dynamically — both essential for plugin systems that load and use types discovered at runtime.
Type type = Type.GetType("MyApp.Plugins.LoggerPlugin");
object instance = Activator.CreateInstance(type)!;
MethodInfo method = type.GetMethod("Log")!;
method.Invoke(instance, new object[] { "Hello from reflection!" });
Real-world example Building a plugin architecture that loads and instantiates plugin classes discovered dynamically from a directory of DLLs.

Common follow-ups: What's the performance cost of Activator.CreateInstance() and MethodInfo.Invoke() compared to a direct 'new' call and method invocation?

Design Patterns in C#

How does the .NET dependency injection container and ASP.NET Core's model binding use reflection and attributes together under the hood?

Advanced
ASP.NET Core scans controller action parameters and constructor parameters via reflection, matching them against registered services (for DI) or incoming request data (for model binding) — attributes like [FromBody], [FromRoute], and [Required] on those parameters guide exactly HOW reflection-based binding should interpret and validate each one at request time.
public class UsersController : ControllerBase {
  private readonly IUserService _service; // resolved via reflection-based DI
  public UsersController(IUserService service) { _service = service; }

  [HttpPost]
  public IActionResult Create([FromBody] CreateUserRequest request) { /* ... */ }
}
Real-world example Understanding how ASP.NET Core 'magically' wires up your controller's dependencies and request parameters without you writing manual binding code.

Common follow-ups: Why is reflection-heavy DI/binding done ONCE at application startup rather than on every single request, for performance reasons?

Dependency Injection & IoC Principles

How would you write a simple reflection-based object mapper that copies matching property values from one object to another of a different type?

Advanced
Iterate the source type's properties via reflection, and for each one, look up a same-named property on the destination type; if found and type-compatible, read the source value with PropertyInfo.GetValue() and write it to the destination with PropertyInfo.SetValue() — this is conceptually what libraries like AutoMapper do internally, with much more sophistication and caching for performance.
public static TDest MapTo<TSource, TDest>(TSource source) where TDest : new() {
  var dest = new TDest();
  var destProps = typeof(TDest).GetProperties();
  foreach (var srcProp in typeof(TSource).GetProperties()) {
    var destProp = destProps.FirstOrDefault(p => p.Name == srcProp.Name && p.PropertyType == srcProp.PropertyType);
    destProp?.SetValue(dest, srcProp.GetValue(source));
  }
  return dest;
}
Real-world example Building a lightweight DTO-to-entity mapper for a small project without pulling in a full mapping library dependency.

Common follow-ups: Why would a production-grade mapper like AutoMapper compile and CACHE this mapping logic instead of using raw reflection on every call?

Generics

How do you use reflection to discover all types in an assembly that implement a specific interface, useful for plugin discovery?

Advanced
Assembly.GetTypes() returns every type defined in an assembly; filter that collection using LINQ combined with Type.IsAssignableFrom() (or the interface Type's .IsAssignableFrom on each candidate) to find only the concrete, non-abstract classes that implement your target interface.
var pluginTypes = Assembly.GetExecutingAssembly()
    .GetTypes()
    .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

foreach (var type in pluginTypes) {
  var plugin = (IPlugin)Activator.CreateInstance(type)!;
  plugin.Execute();
}
Real-world example Building an extensible plugin system that automatically discovers and loads every IPlugin implementation in a loaded assembly.

Common follow-ups: How would you extend this to scan MULTIPLE assemblies loaded from a plugins directory at runtime?

Interfaces & Abstract Classes

Why is reflection generally slower than direct code, and what techniques (like caching or compiled expressions) mitigate this cost?

Advanced
Reflection involves runtime metadata lookups, dynamic type resolution, and boxing/unboxing for value types on every call — significantly slower than direct, JIT-optimized code. Mitigation techniques include caching PropertyInfo/MethodInfo lookups (avoiding repeated GetProperty() calls), or compiling a reflection-based operation into a cached, reusable delegate via System.Linq.Expressions for near-native performance after the first call.
// Slow: repeated reflection lookup every call
void SetNameSlow(object obj, string name) {
  obj.GetType().GetProperty("Name")!.SetValue(obj, name);
}

// Fast: compile once, reuse the delegate many times
var param = Expression.Parameter(typeof(User));
var prop = Expression.Property(param, "Name");
// ... build and compile an Expression<Action<User, string>> once, cache it, invoke repeatedly
Real-world example Optimizing a high-throughput object mapper or serializer that would otherwise be dominated by repeated raw reflection calls.

Common follow-ups: At roughly what call-volume threshold does the compiled-expression approach's upfront cost start paying off over raw reflection?

Generics

How would you use System.Reflection.Emit or source generators as faster, more modern alternatives to runtime reflection for code generation scenarios?

Advanced
System.Reflection.Emit lets you generate and JIT-compile IL code dynamically at runtime for maximum flexibility (though complex to write); modern .NET increasingly favors SOURCE GENERATORS instead, which run at COMPILE TIME to generate real C# source code based on your attributes/types, producing fully AOT-compatible, reflection-free code with zero runtime overhead — the direction libraries like System.Text.Json's source-generated serializers have moved toward.
// Source generator approach (conceptual): attribute triggers compile-time code generation
[JsonSerializable(typeof(User))]
partial class AppJsonContext : JsonSerializerContext { }
// The compiler generates a real, reflection-free serializer for User at BUILD time
Real-world example Choosing source generators over runtime reflection for a library that needs to support Native AOT compilation, where reflection is heavily restricted.

Common follow-ups: Why does Native AOT compilation specifically struggle with (or outright disallow) certain kinds of runtime reflection?

Design Patterns in C#

Showing 1–10 of 11