C# Programming Labs

Master advanced metaprogramming with reflection, custom attributes, and professional unit testing patterns.

Reflection, Attributes & Testing - Module 8

Explore runtime type inspection, metadata, and test-driven development.

Lab 22: Reflection & Type Inspection
Expert
Coding Challenge
Your Task: Use reflection to inspect types at runtime, get properties, methods, and invoke members dynamically.

Detailed Requirements:
1. Get Type information: Type type = typeof(Person); // or at runtime: Type type = obj.GetType(); 2. List properties and methods: PropertyInfo[] props = type.GetProperties(); MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); 3. Get and set property values dynamically: PropertyInfo prop = type.GetProperty("Name"); prop.SetValue(obj, "Alice"); string name = (string)prop.GetValue(obj); 4. Invoke methods dynamically: MethodInfo method = type.GetMethod("Greet"); object result = method.Invoke(obj, new object[] { "World" }); 5. Create instances dynamically: Use Activator.CreateInstance.

💡 Pro Tips:
• Use BindingFlags to filter public/private, static/instance members
• GetProperties() returns only public properties by default
• Reflection is slower than direct calls - cache MethodInfo when possible
• Check for null before invoking to avoid exceptions

Expected Output: Type: Person Properties: Name, Age Methods: Greet, ToString Name value: Alice Age value: 30 Greet result: Hello, World!

Requirements Checklist

Get Type using typeof or GetType()
List properties with GetProperties()
List methods with GetMethods()
Get/Set property values dynamically
Invoke method dynamically
Print reflection results
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Get type: typeof(Person) or obj.GetType()
• Properties: type.GetProperties()
• Methods: type.GetMethods(BindingFlags.DeclaredOnly | ...)
• Invoke: method.Invoke(obj, new object[] { args })
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 23: Custom Attributes
Expert
Coding Challenge
Your Task: Create custom attributes, apply them to classes and members, then read them at runtime using reflection.

Detailed Requirements:
1. Define a custom attribute: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class InfoAttribute : Attribute { public string Author { get; } public string Version { get; set; } public InfoAttribute(string author) { Author = author; } } 2. Apply attribute to class and methods: [Info("Alice", Version = "1.0")] public class Calculator { [Info("Bob")] public int Add(int a, int b) => a + b; } 3. Read attributes at runtime: var attr = type.GetCustomAttribute<InfoAttribute>(); if (attr != null) Console.WriteLine(attr.Author); 4. Check for attribute presence: Use IsDefined or GetCustomAttributes.

💡 Pro Tips:
• AttributeUsage controls where attribute can be applied
• Positional parameters are required; named parameters are optional
• AllowMultiple = true lets same attribute be applied multiple times
• Use generic GetCustomAttribute<T>() for cleaner code

Expected Output: Class attribute: Author=Alice, Version=1.0 Method 'Add' has InfoAttribute: True Method attribute: Author=Bob, Version=

Requirements Checklist

Define custom attribute class extending Attribute
Use AttributeUsage to specify targets
Apply attribute to class and method
Read class attribute with GetCustomAttribute
Read method attribute
Print attribute values
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Define: class MyAttr : Attribute { ... }
• Usage: [AttributeUsage(AttributeTargets.Class)]
• Apply: [MyAttr("value")]
• Read: type.GetCustomAttribute<MyAttr>()
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 24: Unit Testing Patterns
Expert
Coding Challenge
Your Task: Write unit tests following Arrange-Act-Assert pattern, including edge cases and exception testing.

Detailed Requirements:
1. Create a simple test framework simulation: static class Assert { public static void AreEqual<T>(T expected, T actual, string msg = "") { if (!Equals(expected, actual)) throw new Exception($"Assert failed: {msg} Expected {expected}, got {actual}"); } public static void IsTrue(bool condition, string msg = "") { ... } public static void Throws<T>(Action action) where T : Exception { ... } } 2. Write tests with Arrange-Act-Assert: static void TestAdd() { // Arrange var calc = new Calculator(); // Act int result = calc.Add(2, 3); // Assert Assert.AreEqual(5, result, "Add should return sum"); } 3. Test edge cases: Zero, negative numbers, boundaries.
4. Test exceptions: Verify expected exceptions are thrown.
5. Run all tests and report results:

💡 Pro Tips:
• Each test should test ONE thing
• Use descriptive test names
• AAA pattern keeps tests organized
• Test both happy path and edge cases

Expected Output: Running tests... ✓ TestAdd passed ✓ TestAddNegative passed ✓ TestDivide passed ✓ TestDivideByZeroThrows passed 4/4 tests passed

Requirements Checklist

Create Assert helper class with AreEqual, IsTrue
Write test using Arrange-Act-Assert pattern
Test edge case (negative numbers or zero)
Implement Assert.Throws for exception testing
Run multiple tests and count results
Print test results summary
Output
// Click "Run Code" to compile and execute
Hints & Tips
• AAA: Arrange (setup), Act (execute), Assert (verify)
• Assert.AreEqual: Assert.AreEqual(expected, actual)
• Exception test: Assert.Throws<DivideByZeroException>(() => ...)
• Test runner: wrap each test in try/catch to report pass/fail
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below