13 things every C # developer must know

Source: Internet
Author: User

1. Development process

Bugs and flaws in the program often occur in the development process. As long as the tools are used well, it will help to find or avoid problems before you release the program.

Standardize code writing

Standardizing code writing can make your code easier to maintain, especially if your code is developed and maintained by multiple developers or teams. The common tools for enforcing code normalization are: FxCop, StyleCop, and ReSharper.

Developer's language: Before you cover up your mistakes, think carefully about them and analyze the results. Don't expect to rely on these tools to look for errors in your code, because the results may be a far cry from yours.

Code review

Review code and partner programming are common practices, such as developers deliberately reviewing code written by others. Others would like to find bugs in code developers, such as coding errors or execution errors.

Review code is a valuable exercise, because it is very dependent on manual operation, so it is difficult to quantify, the accuracy is not satisfactory.

Static analysis

Static analysis does not require you to run the code, you do not have to write a test case to find out some of the code is not standardized, or some flaws exist. This is a very effective way to find a problem, but you need to have a tool that doesn't have too many false positives. Common static analysis tools for C # are coverity,cat,net,visual Studio Code analyses.

Dynamic analysis

When you run the code, the dynamic analysis tool can help you identify these errors: security vulnerabilities, performance and concurrency issues. This approach is analyzed in the context of the execution period, and because of this, its effectiveness is constrained by the complexity of the code. Visual Studio provides a number of dynamic analysis tools including concurrency Visualizer, IntelliTrace, and Profiling tools.

Manager/Team Leader: Development practice is the best way to practice avoiding common pitfalls. Also pay attention to whether the test tools meet your needs. Try to keep your team's code diagnostic level in a manageable range.


There are a variety of ways to test: unit testing, System integration testing, performance testing, penetration testing, and more. In the development phase, the vast majority of test cases are written by the developer or tester to enable the program to meet the requirements.

The test will only work if the correct code is running. When it comes to functional testing, it can also be used to challenge developers to develop and maintain speed.

Development Best Practices

Spend more time on the tool selection, use the right tools to solve your concerns, and don't add extra work to the developer. Let the analysis tools and tests run smoothly to look for problems, but keep the idea of the code still clearly in the developer's mind.

Position the diagnosed problem as quickly as possible (whether through static analysis or test errors, such as compile warnings, standard violations, problem detection, etc.). If the problem has just been ignored because it is "not concerned" and it is difficult to find it later, it will add a lot of work to the code reviewer and pray that they will not be upset.

Accept these helpful suggestions to improve the quality, security, and maintainability of your code, as well as enhance developers ' ability to develop, coordinate, and improve the predictability of the release code.

Goal Tools Effect
Consistency, maintainability Standardized code writing, static analysis, code review Consistent spacing, naming standards, and good readable formats make it easier for developers to write and maintain code.
Accuracy Code review, static analysis, dynamic analysis, testing The code needs not only the correct syntax, but also the developer's idea to meet the software requirements.
Functional performance Test Tests can verify that most requirements are met: correctness, scalability, robustness, and security.
Security Standardized code writing, code review, static analysis, dynamic analysis, testing Security is a complex problem, and any small vulnerability is a potential threat.
Developer Development Capabilities Standardized code writing, static analysis, testing The developer can quickly correct the error with the help of the tool.
Release predictability Standardized code writing, code review, static analysis, dynamic analysis, testing Streamline the later stages of activity, minimize the wrong positioning cycle, all can let the problem found earlier.
2. Types of traps

One of the main advantages of C # is its flexible type system, and the type of security helps us to find errors earlier. By enforcing strict type rules, the compiler can help you maintain a good code-writing habit. In this respect, the C # language and. The NET Framework provides us with a number of types to accommodate the vast majority of requirements. While many developers have a good understanding of the general type and are aware of the user's needs, some misunderstandings and misuse still exist.

More about. For information on the NTE Framework class library, see the MSDN Library.

Understanding and using standard interfaces

A particular interface involves common C # features. For example, Idiposable allows the use of common resource management languages, such as keyword "using." A good understanding of interfaces can help you write fluent C # code and is easier to maintain.

Avoid using the ICloneable interface-developers never know whether a copied object is a deep copy or a shallow copy. Since there is still no standard judgment on whether the operation of the copied object is correct, there is no way to make it meaningful to use the interface as a contract.

Structural body

Try to avoid writing to structs and treat them as an immutable object to prevent confusion. It becomes more secure to share memory in a scenario like multithreading. Our approach to structs is to initialize the struct when it is created, and if it needs to change its data, it is recommended that a new entity be generated.

correctly understand which standard types/methods are immutable and can return new values (such as strings, dates), which are substituted for those volatile objects (such as List.enumerator).


The value of the string may be empty, so you can use some of the more convenient features at the right time. The value is judged (s). length==0), NullReferenceException errors may occur, while String.IsNullOrEmpty (s) and string.isnullorwhitespace (s) can use null well.

Tag Enumeration

Enumeration types and constants can make your code easier to read, and you can show the meaning of a value by replacing the magic number with an identifier.

If you need to generate a large number of enum types, the Tagged enumeration type is a simpler choice:

public enum Tag {
  None = 0x0,
  Tip = 0x1,
  Example = 0x2
The following method allows you to use multiple tags in a snippet:

snippet.Tag = Tag.Tip | Tag.Example
This method is conducive to data encapsulation, so you don't have to worry about leaking internal collection information when using Tag property getters.

Equality comparisons
There are two types of equality:

1. Reference equality, that is, both references refer to the same object.

2. Numerical equality, that is, two different reference objects can be considered equal.

In addition, C # also provides a lot of equality testing methods. The most common methods are as follows:

== AND! = Operation
Equivalent inheritance method
Static Object.Equal method
IEquatable <T> interface equivalent method
Static Object.ReferenceEquals method
Sometimes it is difficult to figure out the purpose of using references or value equality. To understand this further and make your job better, please refer to:

MSDNhttp: //msdn.microsoft.com/en-us/library/dd183752.aspx

If you want to cover something, don't forget the tools such as IEquatable <T>, GetHashCode () and so on that are provided for us on MSDN.

Pay attention to the impact of untyped containers on overloading, you can consider using "myArrayList [0] == myString" this method. Array elements are "objects" of type compilation stage, so reference equality can be used. Although C # will remind you of these potential errors, during the compilation process, unexpected reference equality will not be reminded in some cases.

3. Class traps encapsulate your data
Classes play a large role in the proper management of data. For performance reasons, classes always cache partial results, or make some assumptions about the consistency of internal data. Making data permissions public will allow you to cache to a certain extent, or make assumptions, and these operations are manifested through the potential impact on performance, security, and concurrency. For example, exposing volatile member items such as generic collections, arrays, etc., allows users to skip you and directly modify the structure.

In addition to controlling objects through access modifiers, attributes also allow you to control exactly what interaction the user has with your object. In particular, the attribute can also let you know the specific situation of reading and writing.

Attributes can help you build a stable API or provide a data binding resource when overwriting data into getters and setters through storage logic.

Never let the property getter be abnormal, and avoid modifying the state of the object. This is a requirement for methods, not a getter for attributes.

For more information about attributes, please refer to MSDN:


Also pay attention to some side effects of getter. Developers are also accustomed to regard the access of member bodies as a common operation, so they often ignore those side effects during code review.

Object initialization
You can assign attributes to a newly created object based on the expression it creates. For example, create a new class C object with a given value for the Foo and Bar properties:

new C {Foo = blah, Bar = blam}
You can also generate an anonymous type entity with a specific attribute name:

var myAwesomeObject = new {Name = ”Foo”, Size = 10};
The initialization process runs before the constructor body, so it is necessary to ensure that this field is initialized before input to the constructor. Since the constructor is not yet running, the initialization of the target domain may not involve "this" anyway.

Transition specification refined input parameters
In order to make some special methods easier to control, it is best to use the least specific type among the methods you use. For example, use List <Bar> to iterate in a method:

public void Foo (List <Bar> bars)
  foreach (var b in bars)
    // do something with the bar ...
For other IEnumerable <Bar> sets, the performance using this method is better, but for the specific parameter List <Bar>, we need to make the set in the form of a table. Select as few types as possible (such as IEnumerable <T>, ICollection <T>, etc.) to ensure the maximum efficiency of your method.

4. Generic
Generics is a very powerful tool in defining independent type structures and design algorithms, which can force types to become safe.

Replacing an untyped set such as an array list with a generic set like List <T> can improve both security and performance.

When using generics, we can use the keyword "default" to get default values for the type (these default values cannot be hard-coded into the implementation). In particular, the default value for numeric types is o, and the default value for reference types and null types is null.

T t = default (T);
5. Type conversion
There are two modes of type conversion. One of the explicit conversion must be called by the developer, and the other implicit conversion is applied to the compiler based on the environment.

The constant o can be implicitly converted to enumerated data. When you try to call a method that contains numbers, you can convert the data to an enumerated type.

Type conversion Description
Tree tree = (Tree) obj; This method can be used when the object is a tree type; if the object is not a tree, an InvalidCast exception may occur.
Tree tree = obj as Tree; This method you can use when predicting whether the object is a tree. If the object is not a tree, null is assigned to the tree. You can use "as" conversion, and then find the return of the null value, and then process it. Since it requires conditionally processed return values, remember to use this conversion only when needed. This extra code may cause some bugs and may reduce the readability of the code.
Conversion usually means one of two things:

1. The performance of RuntimeType can be more special than that of the compiler. The Cast conversion command compiler regards this expression as a more special type. If your assumption is incorrect, the compiler will output an exception to you. For example: converting objects into strings.

2. There is a completely different type of value, which is related to the value of Expression. Cast instructs the compiler to generate code to associate with this value, or to report an exception if there is no value. For example: convert double type to int type.

Both types of Cast have risks. The first Cast asks us a question: "Why can developers know the problem clearly, and why can't the compiler?" If you are in this situation, you can try to change the program so that the compiler can reason out smoothly The right type. If you think that the runtime type of an object is a special type other than compile time type, you can use "as" or "is" operation.

The second type of cast also raises a question: "Why not operate on the target data type in the first step?" If you need the result of the int type, then using int will make more sense than double.

For additional information please refer to:


In some cases, explicit conversion is a correct choice, it can improve the code readability and debug ability, and can also improve the test ability when using appropriate operations.

6. Abnormality Abnormality is not a condition
Exceptions should not often appear in the program flow. They represent the operating environment that developers do not want to see, and these are likely to be irreparable. If you expect a controllable environment, it is much better to actively check the environment than to wait for problems to appear.

Use the TryParse () method to easily convert the formatted string to a number. Regardless of whether the parsing is successful, it will return a boolean result, which is much better than simply returning an exception.

Note the use of exception handling scope
Pay attention to the use of catch and finally blocks when writing code. Because of these undesirable exceptions, control may enter these blocks. The executed code that you expect may be skipped due to an exception. Such as:

Frobber originalFrobber = null;
try {
  originalFrobber = this.GetCurrentFrobber ();
  this.UseTemporaryFrobber ();
  this.frobSomeBlobs ();
finally {
  this.ResetFrobber (originalFrobber);
If GetCurrentFrobber () reports an exception, then the originalFrobber value is still empty when finally blocks are executed. If GetCurrentFrobber cannot be thrown away, why is it inside a try block?

Handle exceptions wisely
Pay attention to deal with your target exceptions in a targeted manner, and only deal with the exception part of the target code. Try not to handle all exceptions, or root exceptions, unless your purpose is to record and re-handle these exceptions. Some exceptions leave the application in a state close to collapse, but it is also much better than it cannot be fixed. Some attempts to fix the code may make the situation worse by mistake.

There are some subtle differences regarding fatal exceptions, especially focusing on the execution of finally blocks, which can affect the safety and debugging of exceptions. For more information, please refer to:


Use a top-level exception handler to handle exceptions safely, and expose some debug problem information. Using the catch block will more safely locate those special situations, so as to solve these problems safely, and then leave some problems to the top exception handler to solve.

If you find an exception, please do something to fix it, and don't put the problem on hold. Shelving will only make the problem more complicated and more difficult to solve.

Including exceptions into a custom exception is particularly useful for code that faces public APIs. Exceptions are part of the visual interface method, which is also controlled by parameters and return values. But this method of spreading many exceptions is very troublesome for the robustness and maintainability of the code.

Throw and ReThrow exceptions
If you want to resolve caught exception at a higher level, then maintain the original abnormal state, and the stack is a good debugging method. However, care must be taken to maintain a balance between debugging and security considerations.

Good options include simply throwing the exception:


Or re-throw the exception as an internal exception:

Throw a new CustomException;

Do not explicitly re-throw a caught exception similar to this:

Throw e;

In this case, the abnormal processing will be restored to the initial state, and debugging will be hindered.

Some exceptions occur outside of the running environment of your code. Instead of using caught blocks, you may need to add processors such as ThreadException or UnhandledException to the target. For example, the Windows Forms exception does not appear in the form processing thread environment.

Atomicity (data integrity)
Never let anomalies affect the integrity of your data model. You need to ensure that your object is in a relatively stable state-so that any operations performed by the class will not violate the law. Otherwise, the use of "recovery" will make your code more confusing and cause further damage.

Consider several ways to modify the order of private domains. If an exception occurs in the process of modifying the order, then your object may not be in an illegal state. Try to get the new value before actually updating the domain, so you can update your domain normally under abnormal security management.

Assign variable types to specific types of values-including Boolean, 32bit or smaller data types and reference types-to ensure that they can be atomic. There is no guarantee for some large data (double, long, decimal). You can think about this more: when sharing multi-threaded variables, use lock statements more.

7. Event
The event and the delegate together provide a method about the class, which reminds the user when something special happens. The value of the delegated event should be called when the event occurs. The event is like a field of the delegate type, when the object is generated, it is automatically initialized to null.

The event is also like a domain with a value of "multicast". This means that one delegate can call other delegates in turn. You can assign a delegate to an event, or you can pass something like-=  + =Operate to control events.

Pay attention to resource competition
If an event is shared by multiple threads, it is possible for another thread to clear all user information before calling it after you check for null—and throw a NullReferenceException.

The standard solution to such problems is to create a copy of the event for testing and invocation. You still need to pay attention that if the delegate is not called correctly, then the user removed in other threads can still continue to operate. You can also use some method to lock the operations in order to avoid some problems.

public event EventHandler SomethingHappened;
private void OnSomethingHappened ()
  // The event is null until somebody hooks up to it
  // Create our own copy of the event to protect against another thread removing our subscribers
  EventHandler handler = SomethingHappened;
  if (handler! = null)
    handler (this, new EventArgs ());
For more information about events and competition, please see:


Don't forget to unhook the event handler
Using an event handler to generate a reference from the handler's resource object to the receiving object for the event resource can protect the garbage collection at the receiving end.

A proper unhook processor can ensure that you do n’t have to waste time calling the delegate because it no longer works, and it does n’t make the memory store useless delegates and unreferenced objects.

8. Properties
Attributes provide a way to inject metadata into assemblies, classes, and their information attributes. They are often used to provide information to consumers of code—such as debuggers, framework tests, and applications—through reflection. You can also define attributes to your users or use predefined attributes, as detailed in the table below:

Property Use Object Purpose
DebuggerDisplay Debugger Debugger display format
InternalsVisibleTo Member access uses specific classes to expose internal members to specify other classes. Based on this method, the test method can be used to protect members, and the persistence layer can use some special hidden methods.
DefaultValue Properties specifies a default value for the property
Be sure to pay more attention to DebuggerStepThrough-otherwise it will make it very difficult to find bugs where this method is applied, and you will also skip a step or push it and redo it.

Debug is an essential part of the development process. In addition to making the opaque part of the operating environment visible, the debugger can also invade the operating environment, and if the debugger is not used, it will cause the application to become different.

Visualize the exception stack
In order to observe the current abnormal state of the framework, you can add the expression "$ exception" to the Visual Studio Watch window. This variable contains the current exception state, similar to what you see in the catch block, but it does not contain the exceptions that are not actually seen in the code that you see in the debugger.

Pay attention to the side effects of the accessor
If your properties have side effects, consider whether you should use features or debugger settings to avoid the debugger from automatically calling getters. For example, your class may have such an attribute:

private int remainingAccesses = 10;
private string meteredData;
public string MeteredData
    if (remainingAccesses--> 0)
      return meteredData;
    return null;
The first time you see this object in the debugger, remainingAccesses will get an integer variable with a value of 10, and MeteredData is null. However, if you hover over remainingAccesses, you will find that its value will become 9. In this way, the debugger property value changes the state of your object.

10. Performance optimization
Plan early, keep monitoring, and optimize later

In the design stage, set practical goals. In the development phase, it makes more sense to focus on the correctness of the code than to fine-tune it. For your goals, you need to monitor more during the development process. You only need to spend time making an adjustment to the program when you have not reached the desired goal.

Please remember to use appropriate tools to ensure the empirical measurement of performance, and make the test in such an environment: the test can be repeated multiple times, and the test process is as consistent as possible with the user's usage habits in reality.

When you test performance, be sure to pay attention to what test goals you really care about. When testing a certain function, does your test include the call of this function or the overhead of loop construction?

We have all heard a lot about the myths of projects that are done much faster than others. Do n’t blindly believe these. Experiments and tests are real things.

Due to CLR optimization, sometimes code that seems inefficient may run faster than code that looks efficient. For example, the CLR optimization loop covers a complete array to avoid checking in the invisible per-element range. Developers often calculate the length of an array before looping it:

int [] a_val = int [4000];
int len = a_val.Length;
for (int i = 0; i <len; i ++)
    a_val [i] = i;
By storing the length in a variable, the CLR will not recognize this part and skip optimization. But sometimes manual optimization can lead to worse performance against humans.

Construct a string
If you plan to connect a large number of strings, you can use System.Text.StringBuilder to avoid generating a large number of temporary strings.

Use batch processing for collections
If you plan to generate and fill a large amount of data known in the collection, due to the existence of redistribution, you can use reserved space to solve the performance and resource problems of generating collections. You can use AddRange method to further optimize the performance, as follows in List <T>:

Persons.AddRange (listBox.Items);
11. Resource Management
The garbage collector can automatically clean up the memory. Even so, all abandoned resources need to be properly handled-especially those that cannot be managed by the garbage collector.

Common sources of resource management issues
Memory fragmentation If there is not enough contiguous virtual address storage space, allocation may fail
Process limitations Processes can usually read all subsets of memory and the resources available to the system.
Resource leakage The garbage collector only manages memory, and other resources need to be properly managed by the application.
Unstable resources Those resources that depend on garbage collectors and finalizers cannot be called immediately when they have not been used for a long time. In fact they may never be called.
Use try / finally blocks to ensure that resources have been reasonably released, or let your class use IDisposable, and a more convenient and safe way to declare.

using (StreamReader reader = new StreamReader (file))
 // your code here
Avoid garbage collector in product code
In addition to calling GC.Collect () to interfere with the garbage collector, you can also consider appropriately releasing or discarding resources. When performing performance tests, if you can bear the consequences of this effect, then you use the garbage collector.

Avoid writing finalizers
Unlike some current rumors, your class does not need Finalizers, and this is only because of the existence of IDisposable! You can let IDisposable give your class the ability to call Dispose in any combination instance already owned, but finalizers can only be used in classes that have unmanaged resources.

Finalizers have a great effect on the interactive Win32-bit handle API, and SafeHandle handles are easy to use.

Don't always assume that your finalizers (always running on the finalizer thread) will interact well with other objects. Those other objects may have been terminated before the process.

12. Concurrency
Dealing with concurrency and multi-threaded programming is a complicated and difficult thing. Before adding concurrency to your program, make sure you have a clear understanding of what you are doing-because there are too many ways!

The situation of multi-threaded software is difficult to predict. For example, it is easy to produce problems such as race conditions and deadlocks, and these problems are not only affecting single-threaded applications. Based on these risks, you should consider multithreading as the last resort. If you have to use multiple threads, try to reduce the need for multiple threads to use memory at the same time. If you must synchronize threads, use the highest level synchronization mechanism possible. At the highest level, these mechanisms are included:

Async-await / Task Parallel Library / Lazy <T>
Lock / monitor / AutoResetEvent
Interlocked / Semaphore
Variable fields and explicit barriers
These are difficult to explain the complexity of C # /. NET. If you want to develop a normal concurrent application, you can refer to O’Reilly's "Concurrency in C # Cookboo".

Use Volatile
Marking a field as "volatile" is an advanced feature, and this setting is often misunderstood by experts. The C # compiler will ensure that the target domain can be acquired and released semantically, but the locked domain is not suitable for this situation. If you do n’t know what to acquire, what semantics to release, and how they affect CPU-level optimization, then avoid using volatile fields for a long time. Instead, higher-level tools such as Task Parallel Library or CancellationToken can be used.

Thread safety and built-in methods
Standard library types often provide ways to make object thread safety easier. For example, Dictionary.TryGetValue (). Using such methods can generally make your code more refreshing, and you don't have to worry about data competition like TOCTOU (a type of time-of-check-time-of-use competition hazard).

Don't lock "this", string, or other ordinary public objects

When using some classes in a multi-threaded environment, pay more attention to the use of locks. Locking string constants, or other public objects, will prevent you from encapsulating in the locked state, and may also cause a deadlock. You need to prevent other code from locking on the same used object, of course your best option is to use private object members.

13. Avoid common mistakes Null
Abuse of null is a common source of program errors. This abnormal operation may cause the program to crash or other abnormalities. If you try to get a null reference as if it is a valid reference value of an object (for example by getting a property or method), then a NullReferenceException will be thrown at runtime.

Static and dynamic analysis tools can check for potential NullReferenceException for you before you release the code. In C #, the reference type is usually caused by the variable not referring to an object. For nullable types and reference types, null can be used. For example: Nullable <Int>, empty commission, cancelled event, "as" conversion failure, and some other situations.

Every null reference exception is a bug. Compared to the problem of finding NullReferenceException, it is better to try to test for null before you use the object. This will make the code easier to read by try / catch block.

When reading data from a database table, be aware that missing values can be expressed as DBNull objects, rather than as null references. Don't expect them to behave like potential null references.

Use binary numbers to represent decimal values
Both Float and double can represent real decimal numbers, but not binary real numbers, and when storing decimal values, binary approximate values can be used when necessary. From a decimal point of view, these binary approximations usually have different precisions and trade-offs, sometimes leading to undesirable results in arithmetic operations. Since floating-point operations are usually performed in hardware, unpredictable hardware conditions can make these differences The difference is more complicated.

When decimal precision is important, decimal is used-for example, economic calculations.

A common mistake is to forget that the structure is a value type, meaning that it is copied and passed by value. For example, you may have seen code like this:

struct P {public int x; public int y;}
void M ()
   P p = whatever;
   p.x = something;
   N (p);
Suddenly one day, the code maintainer decided to restructure the code like this:

void M ()
   P p = whatever;
   Helper (p);
   N (p);
void Helper (P p)
   p.x = something;
Now when N (p) is called in M (), p has an incorrect value. Calling Helper (p) to pass a copy of p is not a reference to p, so the mutation in Helper () is lost. If it is called normally, then the Helper should pass a copy of the adjusted p.

Unexpected calculation
The C # compiler can protect constant overflows during calculations, but not necessarily calculated values. Use the keywords "checked" and "unchecked" to mark what you want to do with the variable.

Don't save the return value
Unlike structures, classes are reference types, and reference objects can be modified appropriately. However, not all object methods can actually modify the referenced object, and some return a new object. When developers call the latter, they need to remember to assign the return value to a variable so that they can use the modified object. In the code review stage, these types of problems usually escape the review and are not discovered. Objects like strings are immutable, so it is never possible to modify these objects. Even so, developers can easily forget these problems.

For example, consider the following string.Replace () code:

string label = "My name is Aloysius";
label.Replace ("Aloysius", "secret");
These two lines of code will print out "My name is Aloysius" after running, because the Raeplace method does not change the value of the string.

Don't invalidate iterators and enumerators
Be careful not to modify the collection while iterating

List <Int> myItems = new List <Int> {20,25,9,14,50};
foreach (int item in myItems)
    if (item <10)
        myItems.Remove (item);
        // iterator is now invalid!
        // you ’ll get an exception on the next iteration
If you run this code, as soon as it loops through the collection of the next item, you will get an exception.

The correct method is to use the second list to save the item you want to delete, and then traverse the list when you want to delete:

List <Int> myItems = new List <Int> {20,25,9,14,50};
List <Int> toRemove = new List <Int> ();
foreach (int item in myItems)
   if (item <10)
        toRemove.Add (item);
foreach (int item in toRemove)
If you are using C # 3.0 or higher, you can try List <T> .RemoveAll:

myInts.RemoveAll (item => (item <10));
Wrong attribute name
When implementing attributes, it should be noted that the name of the attribute is very different from the name of the member item used in the class. It is easy to use the same name without knowing it, and it will also trigger an infinite loop when the attribute is obtained.

// The following code will trigger infinite recursion
private string name;
public string Name
        return Name; // should reference “name” instead.
Also be careful when renaming indirect properties. For example: The data bound in WPF specifies the attribute name as a string. Sometimes unintentional changes to attribute names may inadvertently cause problems that the compiler cannot solve.

13 things every C # developer must know

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.