Chapter 04 Csharp 4 Improving Interoperability

3 min read
Rapid overview

Chapter 04 — C# 4: Improving interoperability

Purpose of this chapter: understand the C# 4 features that make interop and API consumption easier (dynamic, optional/named arguments), and learn generic variance (a key type-system concept used heavily by BCL interfaces).


4.1 Dynamic typing (dynamic)

dynamic defers binding until runtime. The compiler largely stops checking member access and overload resolution for dynamic expressions.

When it’s useful:

  • Interop scenarios (COM, scripting, reflection-heavy code)
  • Adapters around untyped data or late-bound APIs

Why senior interviews care:

  • You should know what you’re trading away: compile-time safety and refactoring confidence.

4.1.1 What changes with dynamic?

  • A call like x.Foo(123) becomes “resolve at runtime” if x is dynamic.
  • Errors that would be compile-time become runtime binder exceptions.

4.1.2 Dynamic behavior beyond reflection (mental model)

Think of dynamic as “late binding with language support”:

  • Often cleaner than manual reflection.
  • Still not free: it can be slower and less predictable than static calls.

4.1.3 Brief look behind the scenes (what to know)

You don’t need implementation details, but be able to state:

  • The runtime resolves the call using the actual runtime type and binder rules.
  • This is different from virtual dispatch (virtual calls still have compile-time binding for signature).

4.1.4 Limitations and surprises

Common surprises:

  • Overload resolution can pick a different method than you expect once runtime types are known.
  • You can accidentally lose generic inference clarity and end up with runtime failures.
  • dynamic can hide null problems until runtime.

4.1.5 Usage suggestions (senior-friendly)

Use dynamic at the edge:

  • Keep dynamic isolated to a small boundary layer.
  • Convert to strong types ASAP (DTOs, domain types).
  • Add tests around the dynamic boundary (since the compiler can’t help you).

In trading/fintech code:

  • Prefer predictable, strongly typed APIs in the core; dynamic is usually a last resort.

4.2 Optional parameters and named arguments

Optional parameters let you omit arguments if defaults exist; named arguments let you specify arguments by name.

static void Log(string message, int level = 1) { /* ... */ }
Log("hi");
Log(message: "hi", level: 3);

4.2.1 Defaults and names

Optional params:

  • Reduce overload counts for small APIs.

Named args:

  • Improve call-site readability (especially for multiple bool/flags).

4.2.2 Determining meaning of a call (important nuance)

The compiler decides which method you mean and which arguments map to which parameters at compile time.

4.2.3 Impact on versioning (big interview point)

Optional argument values are baked into call sites at compile time.

Practical consequence:

  • If you change a default value in a library, callers don’t automatically get the new default until they recompile.

Guideline:

  • Be conservative about optional params in public libraries; consider overloads for versioning safety.

4.3 COM interoperability improvements

This was a major driver for dynamic and optional/named arguments.

Interview relevance today:

  • More about recognizing why the language feature exists than using COM directly.

4.4 Generic variance

Variance is about whether I<X> can be used as I<Y> when X and Y have an inheritance relationship.

4.4.1 Simple examples

  • Covariance (output-only) feels natural: IEnumerable<Dog> can be treated as IEnumerable<Animal>.
  • Contravariance (input-only): Action<Animal> can be treated as Action<Dog> (because it can accept any dog as an animal).

4.4.2 Syntax in interfaces/delegates

  • out T enables covariance (producer).
  • in T enables contravariance (consumer).

4.4.3 Restrictions

Variance is safe only when the type parameter is used in compatible positions:

  • out T shouldn’t be used as an input parameter type.
  • in T shouldn’t be used as a return type.

4.4.4 Variance in practice

Where you’ll see it constantly:

  • IEnumerable<out T>, IReadOnlyList<out T> (producers)
  • IComparer<in T>, IEqualityComparer<in T> (consumers)
  • Delegates like Func<...> and Action<...> (mixed variance patterns)

Interview competency:

  • Explain covariance/contravariance with a concrete example and relate it to API design and substitutability.