13 things that a C # developer must know

Source: Internet
Author: User
13 things every C # developer must know

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:

[Flag]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 approach facilitates the encapsulation of data, so you don't have to worry about having an internal collection information leak when using the Tag property getter.

Equality comparisons (comparison of equality)

There are two types of equality:

1. Reference equality, where both references point to the same object.

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

In addition, C # provides a number of test methods for equality. The most common methods are as follows:

    • = = with! = Action

    • The equivalence method of virtual inheritance of objects

    • Static Object.equal method

    • Iequatable<t> Interface Equivalence method

    • Static Object.referenceequals method

Sometimes it's hard to figure out the purpose of using reference or value equality. To further understand this and to make your job better, see:


If you want to overwrite something, do not forget the tools provided on MSDN such as Iequatable<t>, GetHashCode ().

Note the effect of an untyped container on overloading, consider using the "myarraylist[0] = = MyString" method. Array elements are "objects" of the compile-time type, so referential equality can be used. While C # will alert you to these potential errors, unexpected reference equality will not be alerted in some cases during the compilation process.

3. Traps for classes

Encapsulate your data

Classes play a significant role in the proper management of data. For some performance reasons, a class always caches some of the results, or makes some assumptions about the consistency of the internal data. Exposing data permissions To some extent allows you to cache, or make assumptions, that are manifested by the potential impact on performance, security, and concurrency. For example, exposing variable member items such as generic collections, arrays, and so on, allows the user to skip you and directly modify the structure.


In addition to being able to control objects through access modifiers, attributes also allow you to have an accurate grasp of what interactions users have with your objects. In particular, the attribute also allows you to understand the specifics of reading and writing.

Properties can help you build a stable API or provide a binding resource for data by covering data in getters and setters with storage logic.

Never let the property getter have an exception, and also avoid modifying the object state. This is a requirement for the method, not a getter of the property.

For more information about properties, see MSDN:

http://msdn.microsoft.com/en-us/library/ms229006 (v=vs.120). aspx

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 overlook those side effects when code is censored.

Object initialization

You can assign properties to a newly created object based on the representation it creates. For example, create a new Class C object with the given value for Foo and the Bar property:

New C {Foo=blah, Bar=blam}

You can also generate an entity that has an anonymous type with a specific property name:

var myawesomeobject = new {name= "Foo", size=10};

The initialization process runs before the body of the constructor, so it is necessary to ensure that the domain is initialized before it is entered into the constructor. Because the constructor is not yet running, the initialization of the target domain may not involve "this" anyway.

Input parameters for Transition specification Refinement

To make some special methods easier to control, it is best to use the least specific type in the method you use. For example, use List<bar> in a method to iterate:

public void Foo(List<Bar> bars) 


  foreach(var b in bars)


    // do something with the bar...



For other ienumerable<bar> sets, the performance of this method is better, but for a particular parameter list<bar> we need to make the set behave in the form of a table. Select as few specific types as possible (such as ienumerable<t>, icollection<t> this class) to maximize the efficiency of your approach.

4. Generics

Generics are a powerful tool for defining independent type structures and design algorithms, which can force types to become secure.

Using a generic set like list<t> instead of an array list is an untyped set that can improve security and improve performance.

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

T t = default (t);

5. Type conversion

There are two modes of type conversion. One explicit conversion must be called by the developer, and the other implicit conversion is applied to the compiler based on the environment.

A constant o can be implicitly converted to an enumerated type of data. When you try to invoke a method that contains numbers, you can convert the data to an enumeration type.

Type conversions Describe
Tree = (tree) obj; This method can be used when the object is a tree type, or an invalidcast exception may occur if the object is not a tree.
Tree tree = obj as tree; You can use this method when predicting whether an object is a tree. If the object is not a tree, it assigns a value of NULL to the tree. You can use the "as" conversion, and then find the return of the null value, and then handle it. Since it requires conditional processing of the return value, remember to use this conversion only when needed. This extra code can cause some bugs and may also reduce the readability of your code.

Conversion usually means one of the following two things:

The 1.RuntimeType behaves much more than the compiler shows, and the cast conversion command compiler treats this expression as a more special type. If your assumptions are incorrect, then the compiler will output an exception to you. For example, convert an object to a string.

2. There is a completely different type of value, which is related to the value of expression. The cast command compiler generates code to associate with the value, or to report an exception without a value. For example, convert a double type to an int type.

Both types of cast are risky. The first cast posed a question to us: "Why does the developer know the problem clearly and why the compiler can't?" "If you are in this situation, you can try to change the program so that the compiler can easily infer the correct type." If you think that the runtime type of an object is more specific than the compile time type, you can use "as" or "is" operations.

The second cast also raises the question: "Why not work on the target data type in the first step?" "If you want 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 conversions are the right choice to improve code readability and debug capabilities, and to improve testing capabilities with appropriate operations.

6. Exceptions

Exceptions are not condition

Exceptions should not always appear in the program flow. They represent a running environment that developers don't want to see, and these are probably not fixed. If you expect to get a controlled environment, it's much better to proactively check the environment than to wait for the problem to occur.

The TryParse () method makes it easy to convert a formatted string into a number. Whether or not the parse succeeds, it returns a Boolean result, which is much better than simply returning an exception.

Note Use exception handling scope

Note the use of catch and finally blocks when writing code. Due to these unwanted anomalies, 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();




finally {



If Getcurrentfrobber () reports an exception, the value of Originalfrobber is still empty when finally blocks is executed. If Getcurrentfrobber cannot be thrown away, then why is it inside a try block?

Handle Exceptions wisely

Be aware of dealing with your target exception in a targeted manner and only deal with the exception part of the target code. Try not to handle all exceptions, or root class exceptions, unless your purpose is to record and re-process the exceptions. Some exceptions cause the app to be in a near-crashing state, but it's much better than being able to fix it. Some attempts to fix the code may mistakenly make the situation worse.

There are some subtle differences in the fatal anomalies, especially the implementation of the finally blocks, which can affect the security and debugging of the exception. For more information, see:


Use a top-level exception handler to handle exceptions safely and expose some of the debug's problem information. Using catch blocks is a safe way to locate those special situations, and to resolve them safely, leaving some issues to the top-level exception handlers.

If you find an exception, do something to fix it instead of putting it on hold. Shelving only makes the problem more complex and more difficult to solve.

The exception is included in a custom exception and is particularly useful for code that targets the public API. An exception is part of the visual interface method, which is also controlled by the parameter and return value. However, this diffusion of a lot of unusual methods for the robustness of the code and maintainability of the solution is very troublesome.

throw (throw) with continuation throw (ReThrow) exception

If you want to resolve the caught exception at a higher level, then maintain the original exception state, and the stack is a good debug method. However, care should be taken to maintain a balance between debug and security considerations.

A good choice includes simply continuing to throw the exception:


Or, treat the exception as an inner exception to re-throw:

throw a new Customexception;

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

Throw e;

This will restore the exception handling to its original state and hinder debug.

Some exceptions occur outside of your code's running environment. Instead of using caught blocks, you may need to add processors such as threadexception or unhandledexception to your target. For example, Windows Forms exceptions do not appear in the form processing threading environment.

atomicity (Data integrity)

Never let an exception affect the integrity of your data model. You need to make sure that your object is in a more stable state--so that any action performed by the class will not be violated. Otherwise, the "recover" approach will make your code more confusing and prone to further damage.

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

A variable assignment of a specific type of value-including a Boolean, 32bit, or smaller data type and reference type-ensures that it can be atomic. There is no guarantee that some large data (Double,long,decimal) is used. Think more about this: Use lock statements when sharing multi-threaded variables.

7. Events

Events, together with delegates, provide a way for classes to alert users when something special happens. The value of the delegate event should be called when the event occurs. An event is like a domain of a delegate type that is automatically initialized to null when the object is generated.

The event also resembles a domain with a value of "multicast". This means that a delegate can call another delegate in turn. You can assign a delegate to an event, or you can control the event by doing something like-= to + =.

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 invoking it before you check for null-and throw a NullReferenceException.

The standard workaround for this type of problem is to create a copy of the event for testing and invocation. You still need to be aware that if the delegate is not called correctly, then the user who is removed from the other line thread can still continue the operation. You can also use some method to lock 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 on events and competition, see:


Don't forget to unhook the event handler

Use an event handler to generate a reference from the processor's resource object to the receiving object for the event resource to protect the garbage collection at the receiving end.

The appropriate Unhook processor ensures that you do not have to waste time calling it because the delegate is no longer working, nor does it cause memory to store useless delegates with unreferenced objects.

8. Properties

Property provides a way to inject metadata into an assembly, a class, and its information properties. They are often used to provide information to consumers of code-such as debugger, framework testing, and application-by reflecting this way. You can also define attributes to your users, or use predefined attributes, as described in the following table:

Property Working with objects Objective
DebuggerDisplay Debugger Debugger display Format
InternalsVisibleTo Member Access Use a specific class to expose internal members to specify other classes. Based on this method, the test method can be used to protect the members, and the persistence layer can use some special concealment methods.
DefaultValue Properties Specify a default value for the property

Be sure to pay more attention to DebuggerStepThrough-or else it will make it very difficult to find a bug in the way it is applied, and you can skip a step or push it down and redo it.


Debug is an essential part of the development process. In addition to visualizing the parts of the operating environment that are opaque, debugger can invade the operating environment and will cause the application to become different if you do not use debugger.

Visualizing the exception stack

To observe the current frame exception state, you can add the expression "$exception" into 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 a real exception in the code that is not seen in debugger.

Note the side effects of accessors

If your attributes have side effects, consider whether you should use attributes or debugger settings to avoid debugger automatically calling getter. For example, your class might have one of these properties:

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 debugger, Remainingaccesses gets an integer variable with a value of 10, and metereddata is null. However, if you hover end the remainingaccesses, you will find that its value will become 9. This way the property value of debugger changes the state of your object.

10. Performance optimization

Early planning, continuous monitoring, after-do optimization

At the design stage, set realistic goals. In the development phase, it is more meaningful to focus on the correctness of the code than to make a micro-adjustment. For your goals, you need to monitor more during the development process. Just need to take the time to make an adjustment to the program when you are not achieving the desired goal.

Remember to use the right tools to ensure an empirical measurement of performance, and to put the test in such an environment: it can be tested repeatedly, and the test process is as consistent as possible with the user's usage habits in the real world.

When you test for performance, be sure to pay attention to what you really care about testing goals. Does your test have a call to include this function or the overhead of a loop construct when testing a function?

We have all heard a lot more than others do a lot faster project myth, do not blindly believe that these, testing and testing is the real thing.

Because of the reasons for CLR optimization, sometimes seemingly inefficient code may run faster than the seemingly efficient code. For example, the CLR tuning loop overrides 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 does not recognize this part and skips optimizations. But sometimes manual optimizations can lead to worse performance than humans.

Construct a string

If you intend to concatenate a large number of strings, you can use System.Text.StringBuilder to avoid generating a large number of temporary strings.

Using batch processing for collections

If you plan to build and fill up a large amount of data that is known in the collection, you can use reserved space to resolve the performance and resource problems of the generated collection, due to the presence of redistribution. You can use the AddRange method to further optimize performance, which is handled in list<t> as follows:

Persons.addrange (ListBox.Items);

11. Resource Management

The garbage collector (garbage collector) can automatically clean up memory. Even so, the resources that are discarded need to be handled appropriately-especially those that the garbage collector cannot manage.

Common sources of resource management issues
Memory fragmentation If there is not enough contiguous virtual address storage space, it may cause the allocation to fail
Process limits Processes can usually read all subsets of memory and the resources available to the system.
Resource leaks The garbage collector only manages memory, and other resources need to be properly managed by the application.
Unstable resources Resources that rely on garbage collectors and finalizers (finalizers) cannot be called immediately when they have been unused for a long time. In fact, they may never be called.

Use try/finally blocks to ensure that resources have been properly freed, or that your class uses IDisposable, and that it is easier and more secure to declare.

using (StreamReader reader=new StreamReader (file)) {  //your code here

Avoid garbage collector in the product code

In addition to calling Gc.collect () to interfere with garbage collector, it is also possible to consider releasing or discarding resources appropriately. When performing a performance test, if you can bear the consequences of this effect, you should use garbage collector.

Avoid writing finalizers

Unlike some of the rumors circulating today, your class doesn't need to be finalizers, and it's just because IDisposable exists! You can have IDisposable give your class the ability to call Dispose in any combination instance that you already have, but finalizers can only be used in a resource class that has no management.

Finalizers is primarily useful for interactive Win32 bit handle APIs, and SafeHandle handles are easy to use.

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

12. Concurrency

Dealing with concurrency and multithreaded programming is a complex and difficult task. Before adding concurrency to your program, make sure you know exactly what you're doing-because there are too many doorways!

Multithreaded software can be difficult to predict, such as the issue of competitive 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 multi-threaded simultaneous use of memory. If you must synchronize your threads, use the highest-level synchronization mechanism whenever possible. At the highest level, these mechanisms are included:

    • Async-await/task Parallel library/lazy<t>

    • Lock/monitor/autoresetevent

    • Interlocked/semaphore

    • Variable domain and explicit barrier

These are difficult to explain clearly c#/. NET is a complex place. 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 that is often misunderstood by experts. The C # compiler guarantees that the target domain can be fetched and freed semantics, but the lock's domain does not apply to this situation. If you don't know what to get, what semantics to release, and how they affect CPU-level optimizations, avoid using volatile domains for long. Instead, you can use a higher-level tool, such as a task Parallel library or CancellationToken.

Thread safety and built-in methods

Standard library types often provide a way to make object thread security easier. For example, Dictionary.trygetvalue (). Using such a method can generally make your code more refreshing, and you don't have to worry about competing for data like Toctou (a time-of-check-time-of-use competitive hazard).

Do not lock the "this", the string, or other ordinary public objects

When using some classes in a multithreaded environment, pay more attention to the use of lock. Locking a string constant, or other common object, blocks the encapsulation in your lock state, and may cause deadlocks. You need to block other code from locking on the same object, and of course your best choice is to use private object member items.

13. Avoid Common mistakes


Misuse of NULL is a common source of program errors that can cause a program to crash or other exceptions. If you try to get a null reference, as if it were a valid reference value for an object (for example, by getting a property or method), a NullReferenceException is thrown at run time.

Static and dynamic analysis tools can check out potential nullreferenceexception for you before you publish your code. In C #, a reference type of NULL is usually caused by a variable not being referenced to an object. Null can be used for types with nullable values and for reference type. For example: NULLABLE<INT>, null delegate, logged out event, "as" conversion failed, and some other situation.

Each null reference exception is a bug. Rather than finding NullReferenceException, try to test for NULL before you use the object. This makes it easier for the code to minimize Try/catch block reads.

When reading data from a database table, note that missing values can be represented as DBNull objects instead of as null references. Do not expect them to behave as a potential null reference.

Decimal value represented by a binary number

Both float and double can represent decimal real numbers, but they cannot represent binary real numbers, and can be stored with binary approximations when necessary when storing decimal values. From a decimal point of view, these binary approximations often have different precision and trade-offs, sometimes leading to undesirable results in arithmetic operations. Because floating-point operations are typically performed in hardware, the unpredictability of hardware conditions complicates these differences.

When decimal precision is important, it is necessary to use decimal-for example, economic calculations.

Adjust structure

One common mistake is to forget that a struct 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;



Suddenly, one day, the code maintainer decided to make the code heavy:

void M()


   P p = whatever;




void Helper(P p)



   p.x = something;

Now when n (p) is called in M (), p has an incorrect value. Invoking helper (p) passes a copy of P, not a reference to p, so the mutation in the helper () is lost. If it is called normally, the helper should pass a copy of the adjusted p.

Non-expected calculation

The C # compiler can protect a constant overflow during operation, but not necessarily a computed value. Use "Checked" and "unchecked" two keywords to mark what you want to do with a variable.

Do not save return value

Unlike structs, classes are reference types, and reference objects can be modified appropriately. However, not all object methods can actually modify the reference 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 the modified object can be used. During the code review phase, the types of these problems often escape scrutiny without being discovered. Objects such as strings, which are immutable, are never likely to be modified. Even so, it's easy for developers to forget these questions.

For example, look at the following string. Replace () Code:

String label = "My name is Aloysius"; label. Replace ("Aloysius", "secret");

These two lines of code will print "My name is Aloysius" after it is run, because the Raeplace method does not change the value of the string.

Do not invalidate iterators with enumerators

Be careful not to modify the collection over time

List<Int> myItems = new List<Int>{20,25,9,14,50};

foreach(int item in myItems)


    if (item < 10)



        // iterator is now invalid!

        // you’ll get an exception on the next iteration

If you run this code, it loops through the next set of items, and you get an exception.

The correct way to do this is to use the second list to save the item you want to delete, and then traverse the list when you want to delete it:

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)





foreach(int item in toRemove)


If you are using c#3.0 or later, you can try List<t>. RemoveAll:

Myints.removeall (item = (item < 10));

Property name Error

When implementing a property, be aware that the name of the property differs greatly 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 trigger a dead loop when the property is fetched.

// The following code will trigger infinite recursion

private string name;

public string Name




        return Name;  // should reference “name” instead.

You should also be careful when renaming indirect properties. For example, data that is bound in WPF specifies the property name as a string. Sometimes unintentional changes to the property name may inadvertently cause problems that the compiler cannot resolve.

English original: Things every C # Developer should Know translation: code rural Network

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.