[{"data":1,"prerenderedAt":114},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Ffundamentals\u002Fgenerics":3},{"page":4,"siblings":94,"blog":111},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fdotnet\u002Ffundamentals\u002Fgenerics.md","Generics",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,3,"\u002Fdotnet\u002Ffundamentals\u002Fgenerics",[23,28,32,37,41,45,49,53,57,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"what-are-generics","easy","What are generics and why were they introduced in C# 2.0?","**Generics** let you write type-safe, reusable code where the concrete type is\nspecified by the caller, not the author. They eliminate the need for casting and\nprevent boxing\u002Funboxing for value types.\n\n```csharp\n\u002F\u002F Pre-generics (C# 1): must cast, no type safety, boxes value types\nArrayList list = new ArrayList();\nlist.Add(42);           \u002F\u002F boxes int → object\nint x = (int)list[0];  \u002F\u002F unboxes + cast — runtime error if wrong type\n\n\u002F\u002F With generics (C# 2+): type-safe, no boxing, no cast\nList\u003Cint> nums = new List\u003Cint>();\nnums.Add(42);           \u002F\u002F no boxing\nint y = nums[0];        \u002F\u002F no cast, compiler guarantees the type\n\n\u002F\u002F Generic method:\nT Max\u003CT>(T a, T b) where T : IComparable\u003CT>\n    => a.CompareTo(b) >= 0 ? a : b;\n\nConsole.WriteLine(Max(3, 7));       \u002F\u002F 7\nConsole.WriteLine(Max(\"cat\", \"dog\")); \u002F\u002F \"dog\"\n```\n\nThe CLR **reifies** generics — `List\u003Cint>` and `List\u003Cstring>` are genuinely\ndistinct types at runtime, each with their own JIT-compiled native code. This\nmeans value-type specialisations get zero-overhead native implementations.\n\n**Rule of thumb:** Prefer generics over `object` parameters, `ArrayList`, or\ncasting. One generic implementation beats N typed duplicates every time.\n",{"id":29,"difficulty":14,"q":30,"a":31},"generic-constraints","What are generic type constraints in C# and what kinds exist?","**Type constraints** restrict what types a caller can substitute for a type\nparameter, unlocking members of that type inside the generic implementation.\n\n```csharp\n\u002F\u002F where T : class     — T must be a reference type\n\u002F\u002F where T : struct    — T must be a non-nullable value type\n\u002F\u002F where T : new()     — T must have a public parameterless constructor\n\u002F\u002F where T : SomeBase  — T must derive from SomeBase\n\u002F\u002F where T : ISomething — T must implement ISomething\n\u002F\u002F where T : notnull   — T must be non-nullable (C# 8+)\n\u002F\u002F where T : unmanaged — T must be an unmanaged type (C# 7.3+)\n\nclass Repository\u003CT> where T : class, new()\n{\n    public T CreateDefault() => new T(); \u002F\u002F new() constraint enables this\n}\n\nT Clamp\u003CT>(T value, T min, T max) where T : IComparable\u003CT>\n{\n    if (value.CompareTo(min) \u003C 0) return min;  \u002F\u002F CompareTo available via constraint\n    if (value.CompareTo(max) > 0) return max;\n    return value;\n}\n\nConsole.WriteLine(Clamp(15, 1, 10)); \u002F\u002F 10\n```\n\nMultiple constraints combine with commas: `where T : class, ISomething, new()`.\nYou can constrain multiple type parameters independently.\n\n**Rule of thumb:** Add constraints only when you need to call members on `T`.\nEach constraint narrows the caller's type choices — start unconstrained and\nadd constraints as the implementation demands them.\n",{"id":33,"difficulty":34,"q":35,"a":36},"covariance","hard","What is covariance in C# generics?","**Covariance** means a generic type with a more derived type argument is assignable\nto a generic type with a less derived type argument. In C#, covariance is expressed\nwith the `out` keyword on an interface or delegate type parameter.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> is covariant (out T):\nIEnumerable\u003Cstring> strings = new List\u003Cstring> { \"a\", \"b\" };\nIEnumerable\u003Cobject> objects = strings;  \u002F\u002F valid — covariance!\n\u002F\u002F A string IS-A object, so reading strings as objects is safe\n\n\u002F\u002F IReadOnlyList\u003CT> is covariant:\nIReadOnlyList\u003Cstring> strList = new List\u003Cstring> { \"x\" };\nIReadOnlyList\u003Cobject> objList = strList; \u002F\u002F valid\n\n\u002F\u002F Defining a covariant interface:\ninterface IProducer\u003Cout T>   \u002F\u002F 'out' = covariant\n{\n    T Produce();             \u002F\u002F T only appears in output position — safe\n    \u002F\u002F void Consume(T item); \u002F\u002F would break type safety — input position forbidden\n}\n```\n\nCovariance is safe because you are only **reading** values out of the container —\nthe container will always give you a `string`, and a `string` is always a valid\n`object`. Writing would be unsafe (you could insert a non-string into a\n`List\u003Cstring>` disguised as `List\u003Cobject>`).\n\n**Rule of thumb:** `out T` = covariance = the type flows **out** of the API\n(producer). Safe for read-only interfaces. Familiar examples: `IEnumerable\u003Cout T>`,\n`IReadOnlyList\u003Cout T>`, `Func\u003Cout TResult>`.\n",{"id":38,"difficulty":34,"q":39,"a":40},"contravariance","What is contravariance in C# generics?","**Contravariance** is the reverse: a generic with a **less** derived type argument\nis assignable to one with a **more** derived type argument. Expressed with the `in`\nkeyword — the type parameter only appears in input (consumer) positions.\n\n```csharp\n\u002F\u002F Action\u003CT> is contravariant (in T):\nAction\u003Cobject> printObject = obj => Console.WriteLine(obj);\nAction\u003Cstring> printString = printObject;  \u002F\u002F valid — contravariance!\n\u002F\u002F If you can handle any object, you can certainly handle a string\n\nprintString(\"hello\"); \u002F\u002F works — string is passed to printObject handler\n\n\u002F\u002F IComparer\u003CT> is contravariant:\nIComparer\u003Cobject> objComparer = Comparer\u003Cobject>.Default;\nIComparer\u003Cstring> strComparer = objComparer; \u002F\u002F valid\n\n\u002F\u002F Defining a contravariant interface:\ninterface IConsumer\u003Cin T>   \u002F\u002F 'in' = contravariant\n{\n    void Consume(T item);   \u002F\u002F T only appears in input position — safe\n    \u002F\u002F T Produce();         \u002F\u002F would break type safety — output position forbidden\n}\n```\n\nThe logic: if a method can handle any `object`, it can certainly handle a `string`.\nContravariance is about **consuming** values — a handler for the base type is\nalways compatible with a handler for the derived type.\n\n**Rule of thumb:** `in T` = contravariance = the type flows **into** the API\n(consumer). Familiar examples: `Action\u003Cin T>`, `IComparer\u003Cin T>`,\n`IEqualityComparer\u003Cin T>`.\n",{"id":42,"difficulty":14,"q":43,"a":44},"ienumerable-vs-icollection","What is the difference between `IEnumerable\u003CT>` and `ICollection\u003CT>` in generics?","`IEnumerable\u003CT>` is the minimal read\u002Fiterate interface. `ICollection\u003CT>` extends\nit to add count and mutation operations. Choosing the right abstraction in method\nsignatures controls what callers can pass and what you can do with the argument.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> — iterate only, no count, no add\u002Fremove\nvoid PrintAll\u003CT>(IEnumerable\u003CT> items)\n{\n    foreach (var item in items) Console.WriteLine(item); \u002F\u002F fine\n    \u002F\u002F items.Count — not available\n    \u002F\u002F items.Add(...)  — not available\n}\n\n\u002F\u002F ICollection\u003CT> — adds Count, Add, Remove, Contains, Clear\nvoid AddRange\u003CT>(ICollection\u003CT> target, IEnumerable\u003CT> source)\n{\n    foreach (var item in source) target.Add(item); \u002F\u002F Add available\n    Console.WriteLine(target.Count);               \u002F\u002F Count available\n}\n\n\u002F\u002F IList\u003CT> extends ICollection\u003CT> — adds index access\nvoid SwapFirst\u003CT>(IList\u003CT> list) { (list[0], list[1]) = (list[1], list[0]); }\n```\n\nThe interface hierarchy: `IEnumerable\u003CT>` ← `ICollection\u003CT>` ← `IList\u003CT>`.\nUse the **narrowest** interface that satisfies your needs in method parameters —\nthis maximises what callers can pass (arrays, LINQ queries, custom enumerables).\n\n**Rule of thumb:** Accept `IEnumerable\u003CT>` if you only iterate, `ICollection\u003CT>`\nif you need `Count` or mutation, `IList\u003CT>` if you need index access.\nReturn concrete types (`List\u003CT>`) so callers have the full API.\n",{"id":46,"difficulty":14,"q":47,"a":48},"csharp-vs-java-generics","How do C# generics differ from Java generics?","C# generics are **reified** — the type parameter exists at runtime and each\nclosed generic type (e.g., `List\u003Cint>`, `List\u003Cstring>`) is a distinct CLR type.\nJava generics use **type erasure** — type parameters are removed at compile time\nand replaced with `Object` (or the bound type), leaving only one class at runtime.\n\n```csharp\n\u002F\u002F C# — type parameters survive to runtime:\nvar list = new List\u003Cint>();\nConsole.WriteLine(list.GetType().Name);           \u002F\u002F \"List`1\"\nConsole.WriteLine(list.GetType().GenericTypeArguments[0]); \u002F\u002F System.Int32\n\n\u002F\u002F C# — value type specialisation: List\u003Cint> uses int[] internally, no boxing\nvar ints = new List\u003Cint> { 1, 2, 3 }; \u002F\u002F zero boxing\n\n\u002F\u002F C# — can use typeof on generic params:\nvoid Print\u003CT>() => Console.WriteLine(typeof(T).Name);\nPrint\u003CDateTime>(); \u002F\u002F \"DateTime\"\n\n\u002F\u002F Java equivalent would erase T → Object at runtime\n\u002F\u002F Java: new ArrayList\u003CInteger>() has no Integer info at runtime\n\u002F\u002F Java: no specialised ArrayList\u003Cint> — autoboxing to Integer always required\n```\n\nConsequences of C# reification: `typeof(T)` works inside generics, `is T` checks\nare valid, value-type specialisations avoid boxing, and you get distinct JIT code\nper value-type argument. The cost is larger compiled output for many value-type\nspecialisations.\n\n**Rule of thumb:** C# generics are more powerful and more efficient for value\ntypes than Java generics. Use `typeof(T)` and `default(T)` freely in C# — these\nhave no Java equivalent without reflection hacks.\n",{"id":50,"difficulty":14,"q":51,"a":52},"default-t","What is `default(T)` and when would you use it?","`default(T)` returns the **default value** for type `T`: `0` for numeric types,\n`false` for `bool`, `null` for reference types, and zero-initialised for structs.\nIt is the only way to get a valid zero\u002Fnull for an unknown type parameter.\n\n```csharp\nT GetValueOrDefault\u003CT>(Dictionary\u003Cstring, T> dict, string key)\n{\n    return dict.TryGetValue(key, out T? value) ? value : default(T);\n    \u002F\u002F If T is int  → returns 0\n    \u002F\u002F If T is bool → returns false\n    \u002F\u002F If T is string → returns null\n}\n\n\u002F\u002F C# 7.1+: 'default' literal (type inferred from context)\nT[] CreateArray\u003CT>(int length)\n{\n    var arr = new T[length]; \u002F\u002F already zero\u002Fdefault initialised\n    return arr;\n}\n\n\u002F\u002F Useful in generic algorithms:\nT Min\u003CT>(T[] arr) where T : IComparable\u003CT>\n{\n    T min = default!; \u002F\u002F non-null assertion needed with nullable ref types\n    bool first = true;\n    foreach (var item in arr)\n    {\n        if (first || item.CompareTo(min) \u003C 0) { min = item; first = false; }\n    }\n    return min;\n}\n```\n\n**Rule of thumb:** Use `default(T)` or the `default` literal when you need a\n\"zero\" starting value for a type parameter — it is the generic equivalent of\nwriting `0`, `false`, or `null` for concrete types.\n",{"id":54,"difficulty":14,"q":55,"a":56},"generic-delegates","What are the built-in generic delegates `Action\u003CT>`, `Func\u003CT>`, and `Predicate\u003CT>`?","These BCL delegates cover the vast majority of generic callback needs without\nrequiring custom delegate declarations.\n\n```csharp\n\u002F\u002F Action\u003CT...> — takes up to 16 params, returns void\nAction\u003Cstring> print = s => Console.WriteLine(s);\nAction\u003Cint, int> add = (a, b) => Console.WriteLine(a + b);\nprint(\"hello\");   \u002F\u002F \"hello\"\nadd(2, 3);        \u002F\u002F 5\n\n\u002F\u002F Func\u003CT..., TResult> — takes up to 16 params, returns TResult\nFunc\u003Cint, int, int> multiply = (a, b) => a * b;\nFunc\u003Cstring, int>   parse    = int.Parse;\nConsole.WriteLine(multiply(3, 4)); \u002F\u002F 12\n\n\u002F\u002F Predicate\u003CT> — exactly Func\u003CT, bool>, used in List\u003CT>.Find etc.\nPredicate\u003Cint> isEven = n => n % 2 == 0;\nvar nums = new List\u003Cint> { 1, 2, 3, 4 };\nConsole.WriteLine(nums.FindIndex(isEven)); \u002F\u002F 1\n\n\u002F\u002F LINQ uses Func throughout — these three delegate types compose naturally:\nvar evens = nums.Where(isEven.Invoke).Select(n => n * 10).ToList();\n```\n\n`Predicate\u003CT>` is literally `Func\u003CT, bool>` — they are separate types only for\nhistorical API compatibility (`List\u003CT>` predates LINQ). You can convert with\n`.Invoke` or a lambda wrapper.\n\n**Rule of thumb:** Use `Func\u003C>` for functions, `Action\u003C>` for side effects, and\n`Predicate\u003CT>` only when an API specifically requires it. Never define a custom\nsingle-method delegate unless you need a more descriptive name for API clarity.\n",{"id":58,"difficulty":14,"q":59,"a":60},"generic-interface-multiple","Can a class implement the same generic interface multiple times with different type arguments?","Yes, a class can implement `IInterface\u003CT>` for multiple closed types, but only\nthrough the explicit interface implementation syntax when the method signatures\nwould conflict.\n\n```csharp\ninterface IConverter\u003CT>\n{\n    T Convert(string input);\n}\n\nclass MultiConverter : IConverter\u003Cint>, IConverter\u003Cdouble>\n{\n    \u002F\u002F Explicit implementations avoid member name collision:\n    int IConverter\u003Cint>.Convert(string input) => int.Parse(input);\n    double IConverter\u003Cdouble>.Convert(string input) => double.Parse(input);\n}\n\nvar mc = new MultiConverter();\nint i = ((IConverter\u003Cint>)mc).Convert(\"42\");\ndouble d = ((IConverter\u003Cdouble>)mc).Convert(\"3.14\");\nConsole.WriteLine($\"{i}, {d}\"); \u002F\u002F 42, 3.14\n\n\u002F\u002F Common real-world example — IEquatable\u003CT> and IComparable\u003CT>:\nstruct Temperature : IComparable\u003CTemperature>, IEquatable\u003CTemperature>\n{\n    public double Celsius { get; init; }\n    public int CompareTo(Temperature other) => Celsius.CompareTo(other.Celsius);\n    public bool Equals(Temperature other) => Celsius == other.Celsius;\n}\n```\n\n**Rule of thumb:** A class implementing the same interface for multiple type\nargs is valid but rare. It's most common in adapters or type-bridge scenarios.\nWhen signatures collide, use explicit interface implementation to disambiguate.\n",{"id":62,"difficulty":14,"q":63,"a":64},"typeof-vs-gettype","What is the difference between `typeof(T)` and `t.GetType()` inside a generic method?","`typeof(T)` is a **compile-time** operator that returns the `Type` object for the\nstatic type parameter `T`. `t.GetType()` is a **runtime** call on an instance `t`\nthat returns its actual runtime type — which may be a subclass of `T`.\n\n```csharp\nvoid Inspect\u003CT>(T value)\n{\n    Console.WriteLine(typeof(T).Name);   \u002F\u002F static type parameter\n    Console.WriteLine(value.GetType().Name); \u002F\u002F actual runtime type of the instance\n}\n\nInspect\u003Cobject>(\"hello\");\n\u002F\u002F typeof(T)      → \"Object\"  (T is declared as 'object')\n\u002F\u002F GetType()      → \"String\"  (the actual object is a string)\n\nInspect\u003Cstring>(\"hello\");\n\u002F\u002F typeof(T)      → \"String\"\n\u002F\u002F GetType()      → \"String\"   (same in this case)\n\n\u002F\u002F Use typeof(T) when you need the declared type:\nbool IsValueType\u003CT>() => typeof(T).IsValueType;\nConsole.WriteLine(IsValueType\u003Cint>());    \u002F\u002F True\nConsole.WriteLine(IsValueType\u003Cstring>()); \u002F\u002F False\n```\n\nIn most generic code you want `typeof(T)` — it is a constant, avoids a virtual\ndispatch, and works even when `value` is `null`. Use `GetType()` only when you\nspecifically need to know the **runtime subtype** of the instance.\n\n**Rule of thumb:** `typeof(T)` = the type the author declared. `GetType()` = the\ntype the caller actually passed. They differ when `T` is a base class or interface\nand the instance is a derived type.\n",{"id":66,"difficulty":25,"q":67,"a":68},"generic-list-vs-arraylist","What is the difference between `List\u003CT>` and `ArrayList`, and why should you always prefer `List\u003CT>`?","`ArrayList` stores items as `object` — no type safety, every value type is boxed.\n`List\u003CT>` is generic — type-safe, no boxing, and produces helpful compile-time\nerrors rather than runtime `InvalidCastException`.\n\n```csharp\n\u002F\u002F ArrayList — pre-.NET 2 approach, avoid in new code\nvar old = new ArrayList();\nold.Add(42);        \u002F\u002F boxes int → object (heap allocation)\nold.Add(\"oops\");    \u002F\u002F compiles fine — runtime disaster waiting\nint x = (int)old[1]; \u002F\u002F InvalidCastException at runtime!\n\n\u002F\u002F List\u003CT> — correct approach\nvar list = new List\u003Cint>();\nlist.Add(42);       \u002F\u002F no boxing\n\u002F\u002F list.Add(\"oops\"); \u002F\u002F compile-time error — caught immediately\nint y = list[0];    \u002F\u002F no cast needed\nConsole.WriteLine(list.Count); \u002F\u002F 1\n```\n\n`ArrayList` still exists in .NET for legacy compatibility but is effectively\ndeprecated for new code. The only remaining use case is interoperating with old\nCOM APIs or reflection scenarios where the type is unknown at compile time\n(in which case `List\u003Cobject>` is still cleaner than `ArrayList`).\n\n**Rule of thumb:** Never use `ArrayList`, `Hashtable`, or other non-generic\ncollections in new C# code. Always use their generic equivalents: `List\u003CT>`,\n`Dictionary\u003CTKey, TValue>`, `HashSet\u003CT>`.\n",{"id":70,"difficulty":34,"q":71,"a":72},"generic-static-members","Do generic types share static members across different type arguments?","No. In C#, each **closed generic type** (`List\u003Cint>`, `List\u003Cstring>`) is a\ndistinct CLR type with its own set of static members. A static field on\n`MyClass\u003CT>` is **not shared** between `MyClass\u003Cint>` and `MyClass\u003Cstring>`.\n\n```csharp\nclass Counter\u003CT>\n{\n    public static int Count = 0;\n    public Counter() => Count++;\n}\n\n_ = new Counter\u003Cint>();\n_ = new Counter\u003Cint>();\n_ = new Counter\u003Cstring>();\n\nConsole.WriteLine(Counter\u003Cint>.Count);    \u002F\u002F 2 — own counter\nConsole.WriteLine(Counter\u003Cstring>.Count); \u002F\u002F 1 — separate counter\nConsole.WriteLine(Counter\u003Cdouble>.Count); \u002F\u002F 0 — never instantiated\n\n\u002F\u002F Contrast with a non-generic class — one shared static field:\nclass NonGenericCounter\n{\n    public static int Count = 0;\n    public NonGenericCounter() => Count++;\n}\n\u002F\u002F All instances share NonGenericCounter.Count\n```\n\nThis is a direct consequence of CLR **reification** — each generic instantiation\nis a separate type. It enables type-specific caches (e.g., `EqualityComparer\u003CT>.Default`\ncaches one comparer per `T`) but can be a source of bugs when developers expect\nsharing.\n\n**Rule of thumb:** Never expect a static field on a generic type to be shared\nacross type arguments. If you need global shared state, put it in a non-generic\nouter class or a static class.\n",{"id":74,"difficulty":14,"q":75,"a":76},"open-vs-closed-generic","What is the difference between an open generic type and a closed generic type?","An **open generic type** still has unbound type parameters (e.g., `List\u003CT>`). A\n**closed generic type** has all type parameters substituted with concrete types\n(e.g., `List\u003Cint>`). You can only create instances of closed generic types.\n\n```csharp\n\u002F\u002F Closed type — concrete, instantiable:\nvar list = new List\u003Cint>(); \u002F\u002F List\u003Cint> is a closed type\n\n\u002F\u002F Open type — abstract, used with typeof for reflection:\nType open   = typeof(List\u003C>);          \u002F\u002F open generic — note the \u003C>\nType closed = typeof(List\u003Cint>);       \u002F\u002F closed generic\n\nConsole.WriteLine(open.IsGenericTypeDefinition);  \u002F\u002F True\nConsole.WriteLine(closed.IsGenericTypeDefinition); \u002F\u002F False\nConsole.WriteLine(closed.IsConstructedGenericType); \u002F\u002F True\n\n\u002F\u002F Construct a closed type from an open one at runtime:\nType constructed = open.MakeGenericType(typeof(string));\nobject instance  = Activator.CreateInstance(constructed)!; \u002F\u002F List\u003Cstring>\n\n\u002F\u002F Useful for generic plugin\u002Ffactory systems:\nvar repoType    = typeof(Repository\u003C>).MakeGenericType(entityType);\nvar repoInstance = Activator.CreateInstance(repoType);\n```\n\nOpen generic types appear in reflection-based DI containers and ORMs. For example,\nregistering `typeof(IRepository\u003C>)` → `typeof(Repository\u003C>)` lets the container\nresolve `IRepository\u003CUser>` as `Repository\u003CUser>` automatically.\n\n**Rule of thumb:** You work with open generic types mostly in DI registration and\nreflection. In application code, you always deal with closed types. Use\n`MakeGenericType` when you need to construct a generic type from a runtime\n`Type` object.\n",{"id":78,"difficulty":34,"q":79,"a":80},"generic-math-interfaces","What are generic math interfaces in .NET 7+ and how do they enable numeric generics?",".NET 7 introduced a set of interfaces in `System.Numerics` — `INumber\u003CT>`,\n`IAdditionOperators\u003CTSelf, TOther, TResult>`, `IComparable\u003CT>`, etc. — that allow\nyou to write generic algorithms over numeric types without reflection or casting.\n\n```csharp\nusing System.Numerics;\n\n\u002F\u002F Before .NET 7: had to duplicate Sum\u003Cint>, Sum\u003Cdouble>, Sum\u003Cdecimal> ...\n\u002F\u002F .NET 7+: one generic method works for all numeric types\nT Sum\u003CT>(IEnumerable\u003CT> source) where T : INumber\u003CT>\n{\n    T total = T.Zero;                  \u002F\u002F INumber\u003CT> provides Zero\n    foreach (T item in source)\n        total += item;                 \u002F\u002F += via IAdditionOperators\n    return total;\n}\n\nConsole.WriteLine(Sum(new[] { 1, 2, 3 }));          \u002F\u002F 6    (int)\nConsole.WriteLine(Sum(new[] { 1.1, 2.2, 3.3 }));    \u002F\u002F 6.6  (double)\nConsole.WriteLine(Sum(new[] { 1m, 2m, 3m }));       \u002F\u002F 6    (decimal)\n\n\u002F\u002F Parse any number type generically:\nT Parse\u003CT>(string s) where T : IParsable\u003CT>\n    => T.Parse(s, null);\n\nint i = Parse\u003Cint>(\"42\");\ndouble d = Parse\u003Cdouble>(\"3.14\");\n```\n\nThis capability, called **static abstract interface members** (C# 11), allows\ninterfaces to declare static operators and factory methods that must be implemented\nby conforming types.\n\n**Rule of thumb:** Use `INumber\u003CT>` or the narrower arithmetic interfaces\n(`IAdditionOperators`, `IMultiplyOperators`) when writing library-level numeric\nalgorithms. For application code, concrete types are clearer and simpler.\n",{"id":82,"difficulty":14,"q":83,"a":84},"generic-type-inference","How does C# infer generic type arguments, and when do you have to specify them explicitly?","The C# compiler infers generic type arguments from the **types of the method\narguments** passed at the call site. Inference works only for method type parameters\n— class type parameters always require explicit specification.\n\n```csharp\n\u002F\u002F Compiler infers T from the argument type:\nT Identity\u003CT>(T value) => value;\n\nvar s = Identity(\"hello\");  \u002F\u002F T inferred as string\nvar n = Identity(42);       \u002F\u002F T inferred as int\n\u002F\u002F No need to write Identity\u003Cstring>(\"hello\")\n\n\u002F\u002F Inference fails when T appears only in the return type:\nT Create\u003CT>() where T : new() => new T();\n\u002F\u002F var x = Create();        \u002F\u002F error — cannot infer T from no arguments\nvar x = Create\u003CStringBuilder>(); \u002F\u002F must specify explicitly\n\n\u002F\u002F Partial inference is not allowed — specify all or none:\nvoid Combine\u003CT1, T2>(T1 a, T2 b) { }\nCombine(1, \"hi\");           \u002F\u002F both inferred: T1=int, T2=string\n\u002F\u002F Combine\u003Cint>(\"hi\");      \u002F\u002F compile error — cannot partially specify\n\n\u002F\u002F Return-type inference for delegates\u002Flambdas (C# 10):\nvar square = (int x) => x * x; \u002F\u002F inferred as Func\u003Cint, int>\n```\n\nType inference uses **unification** — it matches each argument's type against the\ncorresponding parameter's declared type to deduce `T`. When multiple arguments\nconstrain the same `T` to different types and neither is convertible to the other,\ninference fails and you must specify explicitly.\n\n**Rule of thumb:** Let the compiler infer when arguments supply all the type\ninformation needed. Specify explicitly when `T` is in the return type only, when\ninference would choose the wrong type, or when you need to override the inferred type\nfor clarity.\n",15,null,{"description":11},"C# generics interview questions — type constraints, covariance and contravariance, reification, generic delegates, and performance implications.","dotnet\u002Ffundamentals\u002Fgenerics","Fundamentals","fundamentals","2026-06-22","1GOXwCbAA_czF6emJ43fMJtMHHM9dL-ajJ1eKt7-GmQ",[95,99,102,103,107],{"subtopic":96,"path":97,"order":98},"CLR Runtime","\u002Fdotnet\u002Ffundamentals\u002Fclr-runtime",1,{"subtopic":100,"path":101,"order":12},"Value vs Reference Types","\u002Fdotnet\u002Ffundamentals\u002Fvalue-vs-reference-types",{"subtopic":6,"path":21,"order":20},{"subtopic":104,"path":105,"order":106},"LINQ","\u002Fdotnet\u002Ffundamentals\u002Flinq",4,{"subtopic":108,"path":109,"order":110},"Nullable Types","\u002Fdotnet\u002Ffundamentals\u002Fnullable-types",5,{"path":112,"title":113},"\u002Fblog\u002Fdotnet-generics-type-constraints-covariance","C# Generics: Type Constraints, Covariance, and Contravariance",1782244117844]