Runtime & concurrency
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
Animal value = new Cat();
Type runtime = value.GetType();
Console.WriteLine($"runtime:{runtime.Name}");
Console.WriteLine($"base-accepts:{typeof(Animal).IsAssignableFrom(runtime)}");
Console.WriteLine($"derived-accepts:{typeof(Cat).IsAssignableFrom(typeof(Animal))}");
class Animal { }
sealed class Cat : Animal { }
Reveal answer and reasoning
The lines are runtime:Cat, base-accepts:True, and derived-accepts:False. The new expression constructs Cat, so GetType returns its runtime Type even though the local declaration is Animal. In the second expression Animal is the target type and the runtime Cat is the source, which is a valid assignment direction. The final expression asks whether Cat can accept the general Animal type, which is not guaranteed.
No object is converted, reclassified, or replaced during these queries. An Animal could represent another subtype or a base instance, so a successful base-target check cannot justify the reverse direction. The common wrong trace prints True twice by thinking inheritance is symmetric. These observations establish this bounded hierarchy only; they do not show a successful constructor, an arbitrary generic conversion, or permission to load a plugin.
A null reference would also need separate handling before GetType could be called.
What a strong answer covers
- GetType returns Cat.
- Base accepts derived, not every reverse assignment.
- The program performs metadata checks without casts.
Common pitfall
Assuming inheritance makes both assignability directions true.
Follow-up questions
- What would a second Animal subtype change?
- Which line would need a guard if value could be null?
Self-review
Choose what to revisit. These marks are your own assessment and are separate from lesson completion.