Mid Questions 1 - 150

 0    150 フィッシュ    marcinbalutpoland
mp3をダウンロードする 印刷 遊びます 自分をチェック
 
質問 English 答え English
M.1.1.1. What is the difference between Tuples and ValueTuples?
学び始める
The differences between tuples and ValueTuples are that tuples are reference types and ValueTuples are value types. Also, ValueTuples fields can be named, while with tuples we are stuck with properties named Item1, Item2, etc.
Also, tuples are immutable while ValueTuples are mutable.
M.1.2.2. Is it possible to have a tuple with more than 8 elements?
学び始める
Tuples are limited to hold up to 8 elements, however, we can bypass this limitation by storing the excessive data in the last property called (for example) “Rest” which is also a tuple, making our tuple nested. This is quite awkward for tuples,
but for ValueTuples we get some help from the compiler - it allows us to use the tuple like it really contained more than 8 elements, for example by using Item12 field. Behind the scenes, the compiler will change this to the usage of tuple. Rest. Item5.
M.2.1.3. What is the difference between "is" and "as" keywords?
学び始める
The "is" keyword checks if the object is of a given type. It returns a boolean result. The "as" keyword casts an object to a given type (it’s applicable only to casting to reference types or nullable types).
M.2.2.4. What is the difference between regular casting and casting with "as" keyword?
学び始める
When casting with "as" fails, it will return null. When regular casting fails, an InvalidCastException will be thrown.
M.2.3.5. Why can we only use the "as" keyword to cast objects to nullable types?
学び始める
Because if casting with "as" fails, null will be returned. Null can only be assigned to nullable types.
M.3.1.6. What is the use of the “using” keyword?
学び始める
The “using” keyword has two main uses: the using directive, which allows using types from other namespaces and to create aliases for namespaces,
and the using statement that defines the scope in which the IDisposable object will be used, and that will be disposed at the scope's end.
M.3.2.7. What are the global using directives?
学び始める
When a type is imported in any file with the global using directive, it is like it was imported in all files in the project. This is convenient when some namespace (like, for example, System. Linq) is used in almost every file in the project.
M.4.1.8. What is the purpose of the “dynamic” keyword?
学び始める
The “dynamic” keyword allows us to bypass static type checking that is done by default by the C# compiler. We can call any operations on dynamic variables and the code will still compile. Whether the operation is available in this object or not
will only be checked at runtime. The “dynamic” keyword is most useful when working with types unknown in our codebase, like types being the result of dynamically-typed languages scripts or COM objects.
M.4.2.9. What is the difference between strongly-typed and weakly-typed programming languages?
学び始める
In weakly-typed languages, variables are automatically converted from one type to another. In strongly-typed languages, this will not be the case.
For example, in C#, which is a strongly-typed language, the “2”+8 expression will not compile, while in weakly-typed Perl it will give 10 as a result.
M.4.3.10. What is the difference between statically-typed and dynamically-typed programming languages?
学び始める
In statically-typed languages, the type checks are done at the compile time, while in dynamically-typed languages they are done at runtime. For example, in C# we can’t pass an integer to a method expecting a string.
In Python, which is dynamically typed, we can, but the execution would result in a runtime error if in this method I would call some operation that is not available in int type.
M.4.4.11. What are COM objects?
学び始める
COM stands for “Component Object Model” and it’s a binary-interface standard for Windows software components. In simple terms, a COM object is something that can be understood by different Windows programs,
and for example, it can allow communication between Excel and C# programs.
M.5.1.12. What are expression-bodied members?
学び始める
Expression-bodied members of a type are members defined with expression body instead of the regular body with braces. Using them allows us to shorten the code significantly.
M.5.2.13. What is an expression?
学び始める
An expression is a piece of code that evaluates to some value. For example “2 + 5” evaluates to 7.
M.5.3.14. What is a statement?
学び始める
A statement is a piece of code that does something but does not evaluate to a value. For example, Console. Writeline(“abc”) is a statement. It does not evaluate to any value, as the Console. Writeline is a void method.
M.6.1.15. What are Funcs and lambda expressions?
学び始める
In C#, we can treat functions like any other types - assign them to variables or pass them as parameters to other functions. The Func and Action types allow us to represent functions.
Lambda expressions are a special way of declaring anonymous functions. They allow us to define functions in a concise way and are most useful when those functions will not be used in a different context.
M.6.2.16. What is the signature of a function that could be assigned to the variable of type Func<int, int, bool>?
学び始める
It would be a function that takes two integers as parameters and returns a bool.
M.6.3.17. What is an Action?
学び始める
Action is a type used to represent void functions. It works similarly to Func, but Func can only represent non-void functions.
M.7.1.18. What are delegates?
学び始める
A delegate is a type whose instances hold a reference to a method with a particular parameter list and return type.
M.7.2.19. What is the difference between a Func and a delegate?
学び始める
Func is a delegate, simply defined by Microsoft, not us. To be more precise, Func is a generic delegate used to represent any function with given parameters and returned type.
A delegate is a broader concept than Func - we can define any delegate we want, and it doesn’t need to be generic at all.
M.7.3.20. What is a multicast delegate?
学び始める
It’s a delegate holding references to more than one function.
M.8.1.21. How does the Garbage Collector decide which objects can be removed from memory?
学び始める
Garbage collector removes those objects, to which no references point. To decide whether a reference pointing to some object exists, the Garbage Collector builds a graph of all objects reachable from root objects of the application,
which are things like references currently stored on the stack or in static fields of classes. If an object will not be included in this graph, it means it’s not needed and can be removed from memory. After the graph of reachability is built,
the Garbage Collector can continue its work and remove the unreachable objects.
M.8.2.22. What is the Mark-and-sweep algorithm?
学び始める
It’s the algorithm that the Garbage Collector implements. According to this algorithm, the GC first marks objects that can be removed (mark phase) and then actually removes them (sweep phase).
M.8.3.23. How many stacks are there in a running. NET application?
学び始める
As many as threads. Each thread has its own stack.
M.8.4.24. What two main algorithms of identifying used and unused objects are implemented by tools similar to. NET Garbage Collector?
学び始める
First is reference counting, which associates a count of references pointing to an object with each object. An example of a language using it is Swift.
Another algorithm is tracing (this one is used in. NET) which builds a graph of reachability starting from the application roots.
M.9.1.25. What are generations?
学び始める
The Garbage Collector divides objects into three generations - 0, 1, and 2 - depending on their longevity. Short-lived objects belong to generation 0, and if they survive their first collection, they are moved to generation 1,
and after that - to generation 2. The Garbage Collector collects objects from generation 0 most often, and from generation 2 least often. This feature is introduced in order to improve Garbage Collector’s performance.
Objects that survived a couple of cycles of the GC’s work tend to be long-lived and they don’t need to be checked upon so often. This way, the Garbage Collector has less work to do, so it can do it faster.
M.9.2.26. What is the Large Objects Heap?
学び始める
It’s a special area of the heap reserved for objects larger than 85 000 bytes. Such objects logically belong to generation 2 from the very beginning of their existence and are pinned.
M.9.3.27. What does it mean that the object is pinned?
学び始める
It means it will not be moved during the memory defragmentation that the Garbage Collector is executing. It is an optimization, as large objects are expensive to move, and it’s hard to find a chunk of memory large enough for them.
M. 10.1.28. What is the difference between Dispose and Finalize methods?
学び始める
The Dispose method is used to free unmanaged resources. The Finalize method is the same thing as the destructor, so it’s the method that is called on an object when it is being cleaned up by the Garbage Collector.
M. 10.2.29. What is the difference between a destructor, a finalizer, and the Finalize method?
学び始める
There is no difference, as they are the same thing. During the compilation, the destructor gets changed to the Finalize method which is commonly called a finalizer.
M. 10.3.30. Does the Garbage Collector call the Dispose method?
学び始める
No. The Garbage Collector is not aware of this method. We must call it ourselves, usually by using the using statement.
M. 10.4.31. When should we write our own destructors?
学び始める
The safest answer is “almost never”. Destructors are very tricky and we don’t even have a guarantee that they will run. Use IDisposable instead.
M. 10.5.32. What are managed and unmanaged resources?
学び始める
The managed resources are managed by the Common Language Runtime. Any objects we create with C# are managed resources. The Garbage Collector is aware of their existence, and once they are no longer needed it will free up the memory they occupy.
That means we don’t need to worry about managed resources cleanup as it is done automatically for us. Unmanaged resources are beyond the realm of the CLR. The Garbage Collector doesn’t know about them, so it will not perform any cleanup on them.
Examples of unmanaged resources are database connections, file handlers, COM objects, opened network connections, etc. We as developers are responsible to perform the cleanup after we are done with those objects.
M. 11.1.33. What are default implementations in interfaces?
学び始める
Starting with C# 8, we can provide methods implementations in interfaces. This feature was mostly designed to make it easier to add new methods to existing interfaces without breaking the existing code.
M. 11.2.34. What can be the reason for using default implementations in interfaces?
学び始める
Default implementations in interfaces are mostly designed to make it easier to add new methods to existing interfaces without breaking the existing code.
Without it, if we add a method to an interface we release it as a public library, we will force everyone who updates this library to provide the implementation immediately - otherwise, their code will not build.
M. 12.1.35. What is deconstruction?
学び始める
Deconstruction is a mechanism that allows breaking a tuple or a positional record into individual variables. It is also possible to define how deconstruction should work for user-defined types by implementing the Deconstruct method.
M. 12.2.36. What is the difference between the destructor and the Deconstruct method?
学び始める
The destructor is a method that’s called on an object when this object is being removed from memory by the Garbage Collector. The Deconstruct method allows the object to be deconstructed into single variables.
It is by default generated for tuples, ValueTuples, and positional records, but we can also define it in custom types.
M. 12.3.37. How can we define deconstruction for types that we did not create and we don’t have access to their source code?
学び始める
We can define the Deconstruct method as an extension method for this type.
M. 13.1.38. Why is “catch(Exception)” almost always a bad idea (and when it is not?)?
学び始める
Using “catch(Exception)” should be avoided, because it catches every kind of exception. When we decide to catch an exception, we should know how to handle it, and it’s not feasible if the exception’s type is unknown.
The acceptable use cases for catching any type of exceptions are: 1. The global catch block that is catching all exceptions not handled elsewhere and shows them to the user. 2. Any catch block in which we rethrow an exception without handling it.
M. 13.2.39. What are the acceptable cases of catching any type of exception?
学び始める
The acceptable use cases for catching any type of exceptions are: 1. The global catch block that is catching all exceptions not handled elsewhere and shows them to the user. 2. Any catch block in which we rethrow an exception without handling it.
M. 13.3.40. What is the global catch block?
学び始める
The global catch block is the catch block defined at the upper-most level of the application, that is supposed to catch any exceptions that hadn’t been handled elsewhere.
It usually logs the exception and shows some information to the user, before stopping the application.
M. 14.1.41. What is the difference between “throw” and “throw ex”?
学び始める
The difference between “throw” and “throw ex” is that “throw” preserves the stack trace (the stack trace will point to the method that caused the exception in the first place) while ”throw ex” does not preserve the stack trace
(we will lose the information about the method that caused the exception in the first place. It will seem like the exception was thrown from the place of its catching and re-throwing)
M. 14.2.42. What is the stack trace?
学び始める
The stack trace is a trace of all methods that have been called, that lead to the current moment of the execution. At the top of the stack trace we have the method that has been called most recently, and at the bottom - the one that has been called first.
Stack trace allows us to locate the exact line in code that was the source of an exception.
M. 14.3.43. Should we use “throw” or “throw ex”, and why?
学び始める
We should use “throw” as it preserves the stack trace and helps us find the original source of the problem.
M. 15.1.44. What is the difference between typeof and GetType?
学び始める
Both typeof keyword and the GetType method are used to get the information about some type. The differences between them are: 1. typeof takes the name of the type we want to inspect, so we must know the type before. typeof is resolved at compile time.
2. GetType is a method that must be executed on an object. Because of that, it is resolved at runtime. This method comes from the System. Object base class, so it is available in any object in C#.
M. 15.2.45. What is the purpose of the GetType method?
学び始める
This method returns the Type object which holds all information about the type of the object it was called on. For example, it contains the type name, list of the constructors, attributes, the base type, etc.
M. 15.3.46. Where is the GetType method defined?
学び始める
It is defined in the System. Object type, which is a base type for all types in C#. This is why we can call the GetType method on objects of any type.
M. 16.1.47. What is reflection?
学び始める
Reflection is a mechanism that allows us to write code that can inspect types used in the application.
For example, using reflection, we can list all fields and their values belonging to a given object, even if at compile time we don’t know what type it is exactly.
M. 16.2.48. What are the downsides of using reflection?
学び始める
Using reflection has a relatively big impact on performance. Also, it makes the code hard to understand and maintain.
It may also tempt some programmers to “hack” some code, for example, to access private fields at runtime, which may lead to unexpected results and hard-to-understand bugs.
M. 17.1.49. What are attributes?
学び始める
Attributes add metadata to a type. In other words, they are a way to add information about a type or method to the metadata which describes that type or method.
M. 17.2.50. What is metadata?
学び始める
Generally speaking, metadata is data providing information about other data. For example, when working with databases, the data stored inside the database is the actual data, while the structure of tables and relations between them is metadata.
In programming, metadata describes types used in an application. We can access it in the runtime using reflection, to get the information about some type, for example, what methods or what constructors it contains.
M. 17.3.51. How to define a custom attribute?
学び始める
To define a custom attribute we must define a class that is derived from the =Attribute base class.
M. 18.1.52. What is serialization?
学び始める
Serialization is the process of converting an object into a format that can be stored in memory or transmitted over a network. For example, the object can be converted into a text file containing JSON or XML, or a binary file.
M. 18.2.53. What are the uses of serialization?
学び始める
It can be used to send objects over a network, or to store objects in a file for later reconstruction, or even to store them in a database.
For example to save a "snapshot" of an object every time a user makes some changes to it, so we can log the history of the changes.
M. 18.3.54. What does the Serializable attribute do?
学び始める
This attribute indicates that instances of a class can be serialized with BinaryFormatter or SoapFormatter. It is not required for XML or JSON serialization.
M. 18.4.55. What is deserialization?
学び始める
Deserialization is the opposite of serialization: it’s using the content of a file to recreate objects.
M. 19.1.56. What is pattern matching?
学び始める
Pattern matching is a technique where you test an expression to determine if it has certain characteristics.
M. 19.2.57. How can we check if an object is of a given type, and cast to it this type in the same statement?
学び始める
We can use pattern matching for that. For example, we could write “if obj is string text”. This way, we will cast the object to the string variable called text, but only if this object is of type string.
M. 20.1.58. How does the binary number system work?
学び始める
The binary number system is used to represent numbers using only two digits - 0 and 1. For example, the number 13 (in the decimal number system) is 1101 in the binary number system.
All data in a computer’s memory is stored as sequences of bits, and so are all numbers.
M. 20.2.59. What is the decimal representation of number 101?
学び始める
It’s 5 because it’s 2 to the power of zero plus two to the power of 2, which gives 1 + 4 = 5.
M. 20.3.60. Why arithmetic operations in programming can give unexpected results, like for example adding two large integers can give a negative number?
学び始める
Because there is a limited number of bits reserved for each numeric type, for example for integer it’s 32 bits. If the result of the arithmetic operation is so large that it doesn’t fit on this amount of bits,
some of the bits of the result will be trimmed, giving an unexpected result that is not valid.
M. 21.1.61. What is the purpose of the “checked” keyword?
学び始める
The “checked” keyword is used to define a scope in which arithmetic operations will be checked for overflow.
M. 21.2.62. What is the purpose of the "unchecked" keyword?
学び始める
This keyword defines a scope in which check of arithmetic overflow is disabled. It makes sense to use it in projects in which the checking for overflow is enabled for an entire project (can be set on the project level settings).
M. 21.3.63. What is a silent failure?
学び始める
It’s a kind of failure that happens without any notification to the users or developers - they are not informed that something went wrong, and the application moves on, possibly in an invalid state.
M. 21.4.64. What is the BigInteger type?
学び始める
It’s a numeric type that can represent an integer of any size - it is limited only by the application’s memory. It should be used to represent gigantic numbers
(remember that max long is over 4 billion times larger than max int, which is a bit more than two billion, so BigInteger should be used instead of long only to represent unthinkably large numbers).
M. 22.1.65. What is the difference between double and decimal?
学び始める
The difference between double and decimal is that double is a floating-point binary number, while decimal is a floating-point decimal number. Double is optimized for performance, while decimal is optimized for precision.
Doubles are much faster, they occupy less memory and they have a larger range, but they are less precise than decimals.
M. 22.2.66. What is the difference between double and float?
学び始める
The only difference is that double occupies 64 bits of memory while float occupies 32, giving double a larger range. Except for that, they work exactly the same.
M. 22.3.67. What is the NaN?
学び始める
NaN is a special value that double and float can be. It means Not a Number, and it’s reserved for representing results of undefined mathematical operations, like dividing infinity by infinity.
M. 22.4.68. What numeric type should we use to represent money?
学び始める
When representing money we should always use decimals.
M. 23.1.69. What is an Array?
学び始める
Array is the basic collection type in C#, storing elements in an indexed structure of fixed size. Arrays can be single-dimensional, multi-dimensional, or jagged.
M. 23.2.70. What is a jagged array?
学び始める
A jagged array is an array of arrays, which can be all of the different lengths.
M. 23.3.71. What are the advantages of using arrays?
学び始める
They are fast when it comes to accessing an element at the given index. They are basic and easy to use and great for representing simple data of size that is known upfront.
M. 23.4.72. What are the disadvantages of using arrays?
学び始める
Arrays are of fixed size, which means once created, they can’t be resized. It means that are not good for representing dynamic collections that grow or shrink over time.
If we want to allocate the memory for all elements that may be stored, there is a chance we will allocate too much and waste it. We can also underestimate and not declare the array big enough for some edge cases.
M. 23.5.73. How to resize an array?
学び始める
It’s not possible. An array is a collection of a fixed size and once created, it can’t be resized.
M. 24.1.74. What is a List?
学び始める
List<T> is a strongly-typed, generic collection of objects. Lists are dynamic, which means we can add or remove the elements from them. It uses an array as the underlying collection type.
As it grows, it may copy the existing array of elements to a new, larger array.
M. 24.2.75. Why it is a good idea to set the Capacity of the List in the constructor if we know the expected count of elements upfront?
学び始める
Because this way we will avoid the performance-costly operation of copying the underlying array into a new, larger one, which happens when we exceed the count of 4, 8, 16... elements.
M. 24.3.76. What’s the time complexity of the Insert method from the List class?
学び始める
The Insert method needs to move some of the elements of the underlying array forward, to make room for the new element. In the worst-case scenario, when we insert an element at the beginning of the List, we will need to move all existing elements.
This means the complexity of this operation is O(N).
M. 25.1.77. What is an ArrayList?
学び始める
An ArrayList is a collection that can store elements of any type, as it considers them all instances of the System. Object. ArrayLists were widely used in older versions of C#, where the generics were not yet available.
Nowadays they should not be used, as their performance is impacted by the fact that they need to box value types.
M. 25.2.78. What is the difference between an array, a List, and an ArrayList?
学び始める
An array is a basic collection of fixed size that can store any declared type of elements. The List is a dynamic collection (it means, its size can change over time) that is generic, so it can also store any declared type of elements.
An ArrayList is a dynamic collection that can store various types of elements at the same time, as it treats everything it stores as instances of the System. Object type.
M. 25.3.79. When to use ArrayList over a generic List<T>?
学び始める
Never, unless you work with a very old version of C#, which did not support generics. Even if you do, you should rather upgrade. NET to a higher version than work with ArrayLists.
M. 26.1.80. What is the purpose of the GetHashCode method?
学び始める
The GetHashCode method generates an integer for an object, based on this object’s fields and properties. This integer, called hash, is most often used in hashed collections like HashSet or Dictionary.
M. 26.2.81. Can two objects of the same type, different by value, have the same hash codes?
学び始める
Yes. Hash code duplications (or “hash code conflicts”) can happen, simply because the count of distinct hash codes is equal to the range of the integer, and there are many types that can have much more distinct objects than this count.
M. 26.3.82. Why it may be a good idea to provide a custom implementation of the GetHashCode method for structs?
学び始める
Because the default implementation uses reflection, and because of that is slow. A custom implementation may be significantly faster, and if we use this struct as a key in hashed collections extensively, it may improve the performance very much.
M. 27.1.83. What is a Dictionary?
学び始める
A Dictionary is a data structure representing a collection of key-value pairs. Each key in the Dictionary must be unique.
M. 27.2.84. What is a hash table?
学び始める
A hash table is a data structure that stores values in an array of collections. The index in the array is calculated using the hash code. It allows quick retrieval of objects with given hashcode. A hash table is the underlying data structure of Dictionary
M. 27.3.85. Will the Dictionary work correctly if we have hash code conflict for two of its keys?
学び始める
Yes. The Dictionary still can tell which key is which using the Equals method, so it will not mistake them only because they have the same hash codes.
M. 27.4.86. Why should we override the Equals method when we override the GetHashCode method?
学び始める
Because the Equals method is needed for the Dictionary to distinguish two keys in case of the hash code conflict, and because of that its implementation should be in line with the implementation of the GetHashCode method.
For example, if GetHashCode returns the social security number for a Person object, it means we consider this number the Person’s identifier. The Equals method should also only compare the social security numbers.
M. 28.1.87. What are indexers?
学び始める
Indexers allow instances of a type to be indexed just like arrays. In this way, they resemble properties except that they take parameters.
For example, a Dictionary<string, int> has an indexer that allows calling “dictionaryVariable[“some key”]” to access the value under some key.
M. 28.2.88. Is it possible to have a class with an indexer accepting a string as a parameter?
学び始める
Yes. We can define indexers with any parameters. An example of such a class can be a Dictionary<string, int> as we access its elements like “dict[“abc”]”.
M. 28.3.89. Can we have more than one indexer defined in a class?
学び始める
Yes. Just like with method overloading, we can have as many indexers as we want, as long as they differ by the type, count, or order of parameters.
M. 29.1.90. What is caching?
学び始める
Caching is a mechanism that allows storing some data in memory, so next time it is needed, it can be served faster.
M. 29.2.91. What are the benefits of using caching?
学び始める
Caching can give us a performance boost if we repeatedly retrieve data identified by the same key. It can help not only with data retrieved from an external data source but even calculated locally if the calculation itself is heavy
(for example some complex mathematical operations).
M. 29.3.92. What are the downsides of using caching?
学び始める
Cache occupies the application’s memory. It may grow over time, and some kind of cleanup mechanism should be introduced to avoid OutOfMemoryExceptions. Such mechanisms are usually based on the expiration time of the data.
Also, the data in the cache may become stale, which means it changed at the source but the old version is cached and used in the application. Because of that, caching is most useful when retrieving data that doesn’t change often.
M. 30.1.93. What are immutable types and what’s their purpose?
学び始める
Immutability of a type means that once an object of this type is created none of its fields of properties can be updated.
Using immutable types over mutable ones gives a lot of benefits, like making the code simpler to understand, maintain and test, as well as making it thread-safe.
M. 30.2.94. What are pure functions?
学び始める
Pure functions are functions whose results only depend on the input parameters, and they do not have any side effects like changing the state of the class they belong to or modifying the objects passed as an input.
M. 30.3.95. What are the benefits of using immutable types?
学び始める
The code using immutable types is simple to understand. Immutable types make it easy to create pure functions. Using immutable types makes it easier to work with multithreaded applications,
as there is no risk that one thread will modify a value that the other thread is using. Immutable objects retain their identity and validity. Mutable objects make testing problematic. Testing code using immutable types is simpler.
M. 30.4.96. What is the non-destructive mutation?
学び始める
The non-destructive mutation is an operation of creating a new object based on another immutable object. The immutable object won’t be modified, but the result of “modification” will become a new object.
The real-life analogy could be adding 7 days to a date of January the 1st. It will not change the date of January the 1st, but it will produce a new date of January the 8th.
M. 31.1.97. What are records and record structs?
学び始める
Records and record structs are new types introduced in C# 9 and10. They are mostly used to define simple types representing data. They support value-based equality. They make it easy to create immutable types.
M. 31.2.98. What is the purpose of the "with" keyword?
学び始める
The “with” keyword is used to create a copy of a record object with some properties set to new values. In other words, it’s used to perform a non-destructive mutation of records.
M. 31.3.99. What are positional records?
学び始める
Positional records are records with no bodies. The compiler generates properties, constructor, and the Deconstruct method for them. They are a shorter way of defining records, but we can’t add custom methods or writable properties to a positional record.
M. 32.1.100. Why does string behave like a value type even though it is a reference type?
学び始める
String is a reference type with the value type semantics. All strings are immutable, which means when they seem to be modified, actually, a new, altered string is created.
String has value-type semantics as this is more convenient for developers, but it can’t be a value type because string objects can be large, and value types are stored on the stack which has a limited size.
M. 32.2.101. What is interning of strings?
学び始める
Interning means that if multiple strings are known to be equal, the runtime can just use a single string, thereby saving memory.
This optimization wouldn’t work if strings were mutable, because then changing one string would have unpredictable results on other strings.
M. 32.3.102. What is the size of the stack in megabytes?
学び始める
It’s 1 MB for 32-bit processes and 4 MB for 64-bit processes.
M. 32.4.103. What is the underlying data structure for strings?
学び始める
It’s an array of chars. Arrays by definition have fixed size, which is a reason why strings are immutable - we couldn’t modify a string by adding new characters to it, because they wouldn’t fit in the underlying array.
M. 33.1.104. What is the difference between string and StringBuilder?
学び始める
String is a type used for representing textual data. StringBuilder is a utility class created for optimal concatenation of strings.
M. 33.2.105. What does it mean that strings are immutable?
学び始める
It means once a string is created, it can’t be modified. When we modify a string, actually a brand-new string is created and the variable that stored it simply has a new reference to this new object.
M. 34.1.106. What is operator overloading?
学び始める
Operator overloading is a mechanism that allows us to provide custom behavior when objects of the type we defined are used as operands for some operators. For example, we can define what will “obj1+obj2” do.
M. 34.2.107. What is the purpose of the "operator" keyword?
学び始める
It is used when overloading an operator for a type.
M. 34.3.108. What is the difference between explicit and implicit conversion?
学び始める
Implicit conversion happens when we assign a value of one type to a variable of another type, without specifying the target type in the parenthesis. For example, it happens when assigning an int to a double.
Explicit conversion requires specifying the type in parenthesis, for example when assigning a double to an int.
M. 35.1.109. What are anonymous types?
学び始める
Anonymous types are types without names. They provide a convenient way of encapsulating a set of read-only properties into a single object without having to explicitly define a type first.
M. 35.2.110. Can we modify the value of an anonymous type property?
学び始める
No. All properties of anonymous types are read-only.
M. 35.3.111. When should we, and when should we not use anonymous types?
学び始める
The best use case for anonymous types is when the type we want to use is simple and local to some specific context and it will not be used anywhere else. It’s very often used as a temporary object in complex LINQ queries. If the type is complex or
we want to reuse it, it should not be anonymous. Also, anonymous types can only provide read-only properties; they can’t have methods, fields, events, etc, so if we need any of those features the anonymous types will not work for us.
M. 35.4.112. Are anonymous types value or reference types?
学び始める
They are reference types since they are classes, but they support value-based Equality with the Equals method.
In other words, two anonymous objects with the same values of properties will be considered equal by the Equals method even if their references are different.
M. 36.1.113. What is cohesion?
学び始める
Cohesion is the degree to which elements of a module belong together. In simpler words, it measures how strong the relationship is between members of a class. High cohesion is a desirable trait of the classes and modules.
M. 36.2.114. Is following the Single Responsibility Principle and keeping high cohesion the same thing?
学び始める
No, but it’s common that a highly cohesive class meets the SRP and vice versa. High cohesion means that the data and methods that belong together, are kept together. If following only the SRP, we could (but it doesn’t mean we should!)
keep splitting classes into smaller pieces until every class would have only one public method. Each of those tiny classes would definitely meet the SRP, as they would only have a single responsibility and single reason to change.
But they wouldn’t be cohesive, as they should belong together.
M. 37.1.115. What is coupling?
学び始める
Coupling is the degree to which one module depends on
another module. In other words, it’s a level of “intimacy” between modules. If a module is very close to another, knows a lot about its details, and will be affected if the other changes, it means they are strongly coupled.
M. 37.2.116. How to recognize strongly couples types?
学び始める
One type uses another type directly, without having any abstraction in between. We often recognize strong coupling the hard way: when we see that even a small change in a class leads to a cascade of changes all around the project.
It proves that the types are not independent.
M. 37.3.117. Which of the SOLID principles allow us to reduce coupling?
学び始める
The Dependency Inversion Principle, which says that classes shouldn’t depend on concrete implementations, but rather on abstractions.
When following this principle we remove the direct way of communication between classes, making them more independent from each other.
M. 38.1.118. What is the Strategy design pattern?
学び始める
The Strategy Design pattern is a pattern that allows us to define a family of algorithms to perform some tasks. The concrete strategy can be chosen at runtime.
M. 38.2.119. What are the benefits of using the Strategy design pattern?
学び始める
It helps to reduce code duplications, makes the code cleaner and more easily testable. It separates the code that needs to be changed often (the particular strategy) from the code that doesn’t change that much (the code using the strategy).
M. 39.1.120. What is the Dependency Injection design pattern?
学び始める
Dependency Injection is providing the objects some class needs (its dependencies) from the outside, instead of having it construct them itself.
M. 39.2.121. What are Dependency Injection frameworks?
学び始める
Dependency Injection frameworks are mechanisms that automatically create dependencies and inject them into objects that need them. They are configurable, so we can decide what concrete types will be injected into objects depending on some abstractions.
They can also be configured to reuse one instance of some type or to create separate instances for each object that needs them. Some of the popular Dependency Injection frameworks in C# are Autofac or Ninject.
M. 39.3.122. What are the benefits of using Dependency Injection?
学び始める
Dependency Injection decouples a class from its dependencies. The class doesn’t make the decision of what concrete type it will use, it only declares in the constructor what interfaces it will need.
Thanks to that, we can easily switch the dependencies according to our needs, which is particularly useful when injecting mock implementations for testing purposes.
M. 40.1.123. What is the Template Method design pattern?
学び始める
Template Method is a design pattern that defines the skeleton of an algorithm in the base class. Specific steps of this algorithm are implemented in derived classes.
M. 40.2.124. What is the difference between the Template Method design pattern and the Strategy design pattern?
学び始める
Both patterns allow specifying what concrete algorithm or a piece of the algorithm will be used. The main difference is that with the Template Method, it is selected at compile-time, as this pattern uses the inheritance.
With the Strategy pattern, the decision is made at runtime, as this pattern uses composition.
M. 41.1.125. What is the Decorator design pattern?
学び始める
Decorator is a design pattern that dynamically adds extra functionality to an existing object, without affecting the behavior of other objects from the same class.
M. 41.2.126. What are the benefits of using the Decorator design pattern?
学び始める
The Decorator pattern allows us to easily add functionality to objects, without touching the original classes, so it’s very much in line with the Open-Closed Principle. It allows us to keep classes simple.
It makes it easy to stack functionalities together, building complex objects from simple classes. It also helps us to be in line with the Single Responsibility Principle, as each class now has a very focused responsibility.
They would be easy to test, maintain, and generally pleasant to works with.
M. 42.1.127. What is the Observer design pattern?
学び始める
The Observer design pattern allows objects to notify other objects about changes in their state.
M. 42.2.128. In the Observer design pattern, what is the Observable and what is the Observer?
学び始める
The Observable is the object that’s being observed by Observers. The Observable notifies the Observers about the change in its state.
M. 43.1.129. What are events?
学び始める
Events are the. NET way of implementing the Observer design pattern. They are used to send a notification from an object to all objects subscribed.
M. 43.2.130. What is the difference between an event and a field of the delegate type?
学び始める
A public field of a delegate type can be invoked from anywhere in the code. Events can only be invoked from the class they belong to.
M. 43.3.131. Why is it a good practice to unsubscribe from events when a subscribed object is no longer needed?
学び始める
Because as long as it is subscribed, a hidden reference between the observable and the observer exists, and it will prevent the Garbage Collector from removing the observer object from memory.
M. 44.1.132. What is Inversion of Control?
学び始める
Inversion of Control is the design approach according to which the control flow of a program is inverted: instead of the programmer controlling the flow of a program, the external sources (framework, services, other components) take control of it.
M. 44.2.133. What is a callback?
学び始める
A callback is an executable code (a method in C#) that gets passed as an argument to some other code.
M. 44.3.134. What is the difference between a framework and a library?
学び始める
According to Martin Fowler: “A library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.
A framework embodies some abstract design, with more behavior built in. In order to use it, you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes.
The framework's code then calls your code at these points.” So in short, the framework relies on Inversion of Control, but the library does not.
M. 45.1.135. What is the “composition over inheritance” principle?
学び始める
“Composition over inheritance” is a design principle stating that we should favor composition over inheritance. In other words, we should reuse the code by rather containing objects within other objects, than inheriting one from another.
M. 45.2.136. What is the problem with using composition only?
学び始める
If we decide not to use inheritance at all, we make it harder for ourselves to define types that are indeed in an “IS-A” relation - so when one type IS the other one. For example, a Dog IS an Animal, or an Employee IS a person.
When implementing such hierarchy with the composition we create very similar types that wrap other types only adding a bit of new functionality, and they mostly contain forwarding methods.
M. 45.3.137. What are forwarding methods?
学び始める
They are methods that don’t do anything else than calling almost identical methods from some other type. Forwarding methods indicate a very close relationship between types, which may mean that one type should be inherited from another.
M. 46.1.138. What are mocks?
学び始める
Mocks are objects that can be used to substitute real dependencies for testing purposes. For example, we don’t want to use a real database connection in unit tests. Instead,
we will replace the object connecting to a database with a mock that provides the same interface, but returns test data. We can set up what will be the results of the methods called on mocks, as well as verify if a particular method has been called.
Mocks are an essential part of unit testing, and it’s nearly impossible to test a real-life application without them.
M. 46.2.139. What is Moq?
学び始める
Moq is a popular mocking library for C#. It allows us to easily create mocks of interfaces, classes, Funcs, or Actions. It gives us the ability to decide what result will be returned from the mocked functions,
as well as validate if some function has been called, how many times, and with what parameters.
M. 46.3.140. What is the relation between mocking and Dependency Injection?
学び始める
Mocking is hard to implement without the Dependency Injection. Dependency Injection allows us to inject some dependencies to a class, so we can choose whether we inject real implementations or mocks.
If the dependency of the class would not be injected but rather created right in the class, we could not switch it to a mock implementation for testing purposes.
M. 47.1.141. What are NuGet packages?
学び始める
NuGet packages contain compiled code that someone else created, that we can reuse in our projects. The tool used to install and manage them is called NuGet Package Manager.
M. 48.1.142. What is the difference between Debug and Release builds?
学び始める
During the Release build, the compiler applies optimizations it finds appropriate. Because of that, the result of the build is often smaller and it works faster.
On the other hand, it’s harder to debug because the compiled result doesn’t match the source code exactly.
M. 48.2.143. How can we execute some piece of code only in the Debug, or only in the Release mode?
学び始める
By placing it inside a #if DEBUG or #if RELEASE conditional preprocessor directives.
M. 49.1.144. What are preprocessor directives?
学び始める
Preprocessor directives help us control the compilation process from the level of the code itself.
We can choose if some part of the code will be compiled or not, we can disable or enable some compilation warnings, or we can even check for the. NET version and execute different code depending on it.
M. 49.2.145. What is the preprocessor?
学び始める
The preprocessor (also known as the “precompiler”) is a program that runs before the actual compiler, that can apply some operations on code before it’s compiled.
M. 49.3.146. How to disable selected warning in a file?
学び始める
By using the #pragma warning disable preprocessor directive. It takes the warning code as the parameter, so for example to disable the “Don’t use throw ex” warning we can do “#pragma warning disable CA2200”.
M. 50.1.147. What are nullable reference types?
学び始める
Nullable reference types is a feature introduced with C# 8, that enables explicit declaration of a reference type as nullable or not. The compiler will issue a warning when it recognizes the code in which a non-nullable object has a chance of being null,
or when we use nullable reference types without null check, risking the NullReferenceException. This feature doesn’t change the actual way of executing C# code; it only changes the generated warnings.
M. 50.2.148. What is the default value of non-nullable reference types?
学び始める
It is null.
M. 50.3.149. What is the purpose of the null-forgiving operator?
学び始める
It allows us to suppress a compiler warning related to nullability.
M. 50.4.150. Is it possible to enable or disable compiler warnings related to nullable reference types on the file level? If so, how to do it?
学び始める
It is possible. We can do it by using #nullable enable and #nullable disable preprocessor directives.

コメントを投稿するにはログインする必要があります。