• 10.Properties


    The common language runtime (CLR) offers two kinds of properties:

    1.parameterless properties, which are simply called properties

    2.parameterful properties, which are called different names by different programming languages.

    1.Parameterless Properties

    Data encapsulation:One of the hallmarks of object-oriented design and programming

      1.means that your type’s fields should never be publicly exposed

      because it’s too easy to write code that improperly uses the fields, corrupting the object’s state.

      There are additional reasons for encapsulating access to a type’s data field. For example, you might want access to a field to execute some side effect, cache some value, or lazily create some internal object. You might also want access to the field to be thread-safe. Or perhaps the field is a logical field whose value isn’t represented by bytes in memory but whose value is instead calculated using some algorithm.

      2.strongly suggest that all of your fields be private. Then, to allow a user of your type to get or set state information, you expose methods for that specific purpose.

      Methods that wrap access to a field are typically called accessor methods.These accessor methods can optionally perform sanity checking and ensure that the object’s state is never corrupted.

      it is easy to make read-only or write-only properties: just don’t implement one of the accessor methods

      3.has two disadvantages.

      First, you have to write more code because you now have to implement additional methods.

      Second, users of the type must now call methods rather than simply refer to a single field name.

      

    properties:a mechanism offered by programming languages and the CLR

      1.alleviates the first disadvantage a little and removes the second disadvantage entirely.

      properties complicate the definition of the type slightly.

      2.You can think of properties as smart fields: fields with additional logic behind them.

      3.The CLR supports static, instance, abstract, and virtual properties.

      4.properties can be marked with any accessibility modifierand defined within an interface.

      5.Each property has a name and a type (which can’t be void).It isn’t possible to overload properties (that is, have two properties with the same name if their types are different).

      6.When you define a property, you typically specify both a get and a set method.

      However, you can leave out the set method to define a read-only property or leave out the get method to define a write-only property.

      7.It’s quite common for the property’s get/set methods to manipulate a private field defined within the type.

      8.however,This field is commonly referred to as the backing field. The get and set methods don’t have to access a backing field.

      For example, the System.Threading.Thread type offers a Priority property that communicates directly with the operating system; the Thread object doesn’t maintain a field for a thread’s priority.

      Another example of properties without backing fields are those read-only properties calculated at run time—for example, the length of a zero-terminated array or the area of a rectangle when you have its height and width. 

      

    compiling

      (1).When you define a property, depending on its definition, the compiler will emit either two or three of the following items into the resulting managed assembly

      1.A method representing the property’s get accessor method. This is emitted only if you define a get accessor method for the property.

      2.A method representing the property’s set accessor method. This is emitted only if you define a set accessor method for the property.

      3.A property definition in the managed assembly’s metadata. This is always emitted.

      (2)compilers  emitting the accessor methods, also emit a property definition entry into the managed assembly’s metadata for each property defined in the source code.This entry contains some flags and the type of the property, and it refers to the get and set accessor methods.

      This information exists simply to draw an association between the abstract concept of a “property” and its

    accessor methods.

      Compilers and other tools can use this metadata, which can be obtained by using the System.Reflection.PropertyInfo class.

      The CLR doesn’t use this metadata information and requires only the accessor methods at run time.

      (3)C# has built-in support for properties. When the C# compiler sees code that’s trying to get or set a property, the compiler actually emits a call to one of these methods.

      If you’re using a programming language that doesn’t directly support properties, you can still access properties by calling the desired accessor method. The effect is exactly the same; it’s just that the source code doesn’t look as pretty.

    Automatically Implemented Properties  

      1.If you are creating a property to simply encapsulate a backing field, then C# offers a simplified syntax known as automatically implemented properties (AIPs),

      2.When you declare a property and do not provide an implementation for the get/set methods,then the C# compiler will automatically declare for you a private field. 

      3.when you use AIPs, the property must be readable and writable; that is,the compiler must produce both get and set methods.

      This makes sense because a write-only field is not useful without the ability to read its value; likewise, a read-only field would always have its default value.

      In addition, because you do not know the name of the compiler-generated backing field, your code must always access the property by using the property name.

      And, if you decide you want to explicitly implement one of the accessor methods, then you must explicitly implement both accessor methods and you are not using the AIP feature anymore.

      For a single property, the AIP feature is an all-or-nothing deal. 

      

    what the value of doing this is(AIPs), as opposed to just declaring a public String field called Name?

      there is a big difference.

      Using the AIP syntax means that you have created a property. Any code that accesses this property is actually calling get and set methods.

      If you decide later to implement the get and/or set method yourself instead of accepting the compiler’s default implementation, then any code that accesses the property will not have to be recompiled.

       However,if you declared Name as a field and then you later change it to a property, then all code that accessed the field will have to be recompiled so that it now accesses the property methods.

    suggestion:

       1.Personally, I do not like the compiler’s AIP feature, so I usually avoid it for the following reason:

      The syntax for a field declaration can include initialization so that you are declaring and initializing the field in one line of code.However, there is no convenient syntax to set an AIP to an initial value.

      Therefore, you must explicitly initialize each AIP in each constructor method.

      2.The runtime serialization engines persist the name of the field in a serialized stream.

      The name of the backing field for an AIP is determined by the compiler, and it could actually change the name of this backing field every time you recompile your code, negating the ability to deserialize instances of any types that contain an AIP.

      Do not use the AIP feature with any type you intend to serialize or deserialize.

      3.When debugging, you cannot put a breakpoint on an AIP get or set method, so you cannot easily detect when an application is getting or setting this property.

      You can set breakpoints on manually implemented properties, which can be quite handy when tracking down bugs.

    Defining Properties Intelligently

    don’t like properties, beacause it look like fields, but they are methods. This has been known to cause a phenomenal amount of confusion。

    there are many assumptions that the programmer makes that may not be true for a property:

      1.A property may be read-only or write-only; field access is always readable and writable. If you define a property, it is best to offer both get and set accessor methods.

      2.A property method may throw an exception; field access never throws an exception.

      3.A property cannot be passed as an out or ref parameter to a method; a field can

      

      

      4.A property method can take a long time to execute; field access always completes immediately.

      A common reason to use properties is to perform thread synchronization, which can stop the thread forever, and therefore, a property should not be used if thread synchronization is required. In that situation, a method is preferred.

      Also, if your class can be accessed remotely (for example, your class is derived from System.MarshalByRefObject), calling the property

    method will be very slow, and therefore, a method is preferred to a property.

      In my opinion,classes derived from MarshalByRefObject should never use properties.

      5.If called multiple times in a row, a property method may return a different value each time;a field returns the same value each time.   

      The System.DateTime class has a read-only Now property that returns the current date and time. Each time you query this property, it will return a different value. This is a mistake, and Microsoft wishes that they could fix the class by making Now a method instead of a property.

      Environment’s TickCount property is another example of this mistake.

      6.A property method may cause observable side effects; field access never does.

      In other words,a user of a type should be able to set various properties defined by a type in any order he or she chooses without noticing any different behavior in the type.

      7.A property method may require additional memory or return a reference to something that is not actually part of the object’s state, so modifying the returned object has no effect on the original object; querying a field always returns a reference to an object that is guaranteed to be part of the original object’s state.

      Working with a property that returns a copy can be very confusing to developers, and this characteristic is frequently not documented.

    people use properties far more often than they should.

      there are very few circumstances in which defining a property is actually useful and will not cause confusion for developers.

      The only thing that properties buy you is some simplified syntax; there is no performance benefit compared to calling a non-property method, and understandability of the code is reduced.

    Object and Collection Initializers

    使用:

       1.It is very common to construct an object and then set some of the object’s public properties (or fields). To simplify this common programming pattern, the C# language supports a special object initialization syntax.

      C# also lets you omit the parentheses before the open brace if you want to call a parameterless constructor.

      ==

      2.If a property’s type implements the IEnumerable or IEnumerable<T> interface, then the property is considered to be a collection, and initializing a collection is an additive operation as opposed to a replacement operation.

      =

      When compiling this code, the compiler sees that the Students property is of type List<String> and that this type implements the IEnumerable<String> interface. Now, the compiler assumes that the List<String> type offers a method called Add (because most collection classes actually offer an Add method that adds items to the collection). The compiler then generates code to call the collection’s Add method.

      If the property’s type implements IEnumerable or IEnumerable<T> but the type doesn’t offer an Add method, then the compiler does not let you use the collection initialize syntax to add items to the collection; instead, the compiler issues something like the following message: error CS0117: ' System.Collections.Generic.IEnumerable<string> ' does not contain a definition for 'Add'.

      Some collection’s Add methods take multiple arguments—for example, Dictionary’s Add method.

      public void Add(TKey key, TValue value);

      You can pass multiple arguments to an Add method by using nested braces in a collection initializer

      

      3.The real benefit of the object initializer syntax is that it allows you to code in an expression context (as opposed to a statement context), permitting composability of functions, which in turn increases code readability.

      For more about composability of functions, see the “Extension Methods” section in Chapter 8, “Methods.”

      

    Anonymous Types

    使用

       1.allows you to automatically declare an immutable tuple type by using a very simple and succinct syntax.

      A tuple type is a type that contains a collection of properties that are usually related to each other in some way

      

      2.Anonymous types are most commonly used with the Language Integrated Query (LINQ) technology. 

      where you perform a query that results in a collection of objects that are all of the same anonymous type. Then, you process the objects in the resulting collection. All this takes place in the same method.

       

      3.Instances of anonymous types are not supposed to leak outside of a method.

      A method cannot be prototyped as accepting a parameter of an anonymous type because there is no way to specify the anonymous type.

      Similarly, a method cannot indicate that it returns a reference to an anonymous type. Although it is possible to treat an instance of an anonymous type as an Object (because all anonymous types are derived from Object),

      there is no way to cast a variable of type Object back into an anonymous type because you don’t know the name of the anonymous type at compile time.

      If you want to pass a tuple around, then you should consider using the System.Tuple type .

    compiling:

      1.

      the compiler infers the type of each expression, creates private fields of these inferred types, creates public read-only properties for each of the fields, and creates a constructor that accepts all these expressions.

      The constructor’s code initializes the private read-only fields from the expression results passed in to it.

      In addition, the compiler overrides Object’s Equals, GetHashCode, and ToString methods and generates code inside all these methods. 

      In effect, the class that the compiler generates looks like the following. 

      

      

      The compiler generates Equals and GetHashCode methods so that instances of the anonymous type can be placed in a hash table collection.

      The properties are readonly as opposed to read/write to help prevent the object’s hashcode from changing. Changing the hashcode for an object used as a key in a hashtable can prevent the object from being found.

       The compiler generates the ToString method to help with debugging. In the Visual Studio debugger, you can place the mouse cursor over a variable that refers to an instance of an anonymous type, and Visual Studio will invoke the ToString method and show the resulting string in a datatip window.

      By the way, Visual Studio’s IntelliSense will suggest the property names as you write code in the editor—a very nice feature.

        2.supports two additional syntaxes for declaring a property inside an anonymous type where it can infer the property names and types from variables

      

      the compiler determines that the first property should be called Name. Because Name is the name of a local variable, the compiler sets the type of the property to be the same type as the local variable: String.

      For the second property, the compiler uses the name of the field/property: Year. Year is an Int32 property of the DateTime class, and therefore the Year property in the anonymous type will also be an Int32.

      Now, when the compiler constructs an instance of this anonymous type, it will set the instance’s Name property to the same value that is in the Name local variable so the Name property will refer to the same "Grant" string. The compiler will set the instance’s Year property to the same value that is returned from dt’s Year property.

      3.The compiler is very intelligent about defining anonymous types. If the compiler sees that you are defining multiple anonymous types in your source code that have the identical structure, the compiler will create just one definition for the anonymous type and create multiple instances of that type.

      By “same structure,” I mean that the anonymous types have the same type and name for each property and that these properties are specified in the same order.

      Because the two variables are of the same type, we get to do some cool things, such as checking whether the two objects contain equal values and assigning a reference to one object into the other’s variable

      

      In the preceding code examples, the type of variable o1 and the type of variable o2 will be the same type because the two lines of code are defining an anonymous type with a Name/String property and a Year/Int32 property, and Name comes before Year.

    The System.Tuple Type

    In the System namespace, Microsoft has defined several generic Tuple types (all derived from Object) that differ by arity (the number of generic parameters).

    示例:

      

      1.it is very important that the producer and consumer of the Tuple have a clear understanding of what is being returned in the Item# properties.

      With anonymous types, the properties are given actual names based on the source code that defines the anonymous type.

      With Tuple types, the properties are assigned their Item# names by Microsoft and you cannot change this at all. Unfortunately, these names have no real meaning or significance, so it is up to the producer and consumer to assign meanings to them. This also reduces code readability and maintainability so you should add comments to your code explaining what the producer/consumer understanding is.

      2.The compiler can only infer generic types when calling a generic method, not when you are calling a constructor.

      For this reason, the System namespace also includes a non-generic, static Tuple class containing a bunch of static Create methods that can infer generic types from arguments.

      This class acts as a factory for creating Tuple objects, and it exists simply to simplify your code.

       

      If you want to create a Tuple with more than eight elements in it, then you would pass another Tuple for the Rest parameter as follows.

      

    特点:

      1.Like anonymous types, after a Tuple is created, it is immutable (all properties are read-only). 

      2.the Tuple classes also offer CompareTo, Equals, GetHashCode, and ToString methods, as well as a Size property. In addition, all the Tuple types implement the IStructuralEquatable, IStructuralComparable, and IComparable interfaces so that you can compare two Tuple objects with each other to see how their fields compare with each other.

    ExpandoObject

    System.Dynamic.ExpandoObject class (defined in the System.Core.dll assembly) 

    When you use this class with C#’s dynamic type , you have another way of grouping a set of properties (key/value pairs) together.

    The result is not compile-time type-safe, but the syntax looks nice (although you get no IntelliSense support), and you can pass ExpandoObject objects between C# and dynamic languages like Python.

    2.Parameterful Properties

    properties parameterless properties:

      the get accessor methods for the properties accepted no parameters 

      because they have the feel of accessing a field

    parameterful properties:

      whose get accessor methods accept one or more parameters and whose set accessor methods accept two or more parameters.

      Different programming languages expose parameterful properties in different ways.

      languages use different terms to refer to parameterful properties: C# calls them indexers and Visual Basic calls them default properties

    parameterful properties (indexers):

      1.exposed using an array-like syntax.

      an indexer as a way for the C# developer to overload the [] operator

      

      

      2.All indexers must have at least one parameter, but they can have more. These parameters (as well as the return type) can be of any data type (except void).

      3.It’s quite common to create an indexer to look up values in an associative array.

      In fact, the System.Collections.Generic.Dictionary type offers an indexer that takes a key and returns the value associated with the key.

      Unlike parameterless properties, a type can offer multiple, overloaded indexers as long as their signatures differ.

      4.an indexer’s set accessor method contains a hidden parameter, called value in C#.

      Like a parameterless property’s set accessor method.

      This parameter indicates the new value desired for the “indexed element.”

      5.the CLR treats parameterful properties just as it does parameterless properties.to the CLR,each is simply a pair of methods and a piece of metadata defined within a type.  

      6. C# doesn’t offer syntax allowing a developer to define a static indexer property,although the CLR does support static parameterful properties.

      different programming languages require different syntax to create and use parameterful properties.

       beacuse C# requires this[...] as the syntax for expressing an indexer was purely a choice made by the C# team. What this choice means is that C# allows indexers to be defined only on instances of objects. 

      7.change the default name, Item, given to your indexer’s get and set accessor methods. 

      C# allows you to rename these methods by applying the System.Runtime.CompilerServices.IndexerNameAttribute custom attribute to the indexer. 

      

      Now the compiler will emit methods called get_Bit and set_Bit instead of get_Item and set_Item.

      When compiling, the C# compiler sees the IndexerName attribute, and this tells the compiler how to name the methods and the property metadata; the attribute itself is not emitted into the assembly’s metadata. 

      8.In C#, a single type can define multiple indexers as long as the indexers all take different parameter sets.

      In other programming languages, the IndexerName attribute allows you to define multiple indexers with the same signature because each can have a different name.

      The reason C# won’t allow you to do this is because its syntax doesn’t refer to the indexer by name; the compiler wouldn’t know which indexer you were referring to.

      

      causes the compiler to generate the fellowing message: error C0111: Type 'SomeType' already defines a member called 'this' with the same parameter types.

      You can clearly see that C# thinks of indexers as a way to overload the [] operator, and this operator can’t be used to disambiguate parameterful properties with different method names and identical parameter sets.

      8.Some programming languages might not support parameterful properties. To access a parameterful property from one of these languages, you must call the desired accessor method explicitly.

      9.To the CLR, there’s no difference between parameterless properties and parameterful properties, so you use the same System.Reflection.PropertyInfo class to find the association between a parameterful property and its accessor methods.

    compilng:

      When the C# compiler sees code that is trying to get or set an indexer, the compiler actually emits a call to one of these methods.

      (1) the compiler will emit either two or three of the following items into the resulting managed assembly,Because the CLR treats parameterful properties just as it does parameterless properties.

      1.A method representing the parameterful property’s get accessor method. This is emitted only if you define a get accessor method for the property.

      2.A method representing the parameterful property’s set accessor method. This is emitted only if you define a set accessor method for the property.

        3.A property definition in the managed assembly’s metadata, which is always emitted. There’s no special parameterful property metadata definition table because, to the CLR, parameterful properties are just properties.

      the compiler compiles the indexer as though the original source code were written as follows

      

      (2)The compiler automatically generates names for these methods by prepending get_ and set_ to the indexer name.

      Because the C# syntax for an indexer doesn’t allow the developer to specify an indexer name, the C# compiler team had to choose a default name to use for the accessor methods; they chose Item. Therefore, the method names emitted by the compiler are get_Item and set_Item.

      When examining the .NET Framework Reference documentation, you can tell if a type offers an indexer by looking for a property named Item

    Selecting the Primary Parameterful Property:

      question:What if a type is defined in a programming language that does allow the developer to define several parameterful properties?How can this type be consumed from C#?

      answer:

      1. a type must select one of the parameterful property names to be the default property by applying an instance of System.Reflection.DefaultMemberAttribute to the class itself.

      For the record, DefaultMemberAttribute can be applied to a class, a structure, or an interface.

      In C#, when you compile a type that defines a parameterful property, the compiler automatically applies an instance of DefaultMember attribute to the defining type and takes it into account when you use the IndexerName attribute.  

      For a language that supports several parameterful properties, one of the property method names must be selected and identified by the type’s DefaultMember attribute.

      This is the only parameterful property that C# will be able to access.

      2.This attribute’s constructor specifies the name that is to be used for the type’s default parameterful property.

      So, in C#, if you define a type that has a parameterful property and you don’t specify the IndexerName attribute, the defining type will have a DefaultMember attribute indicating Item. If you apply the IndexerName attribute to a parameterful property, the defining type will have a DefaultMember attribute indicating the string name specified in the IndexerName attribute.

      Remember, C# won’t compile the code if it contains parameterful properties with different names

     

    3.The Performance of Calling Property Accessor Methods

      1.For simple get and set accessor methods, the just-in-time (JIT) compiler inlines the code so that there’s no run-time performance hit as a result of using properties rather than fields.

      Because property accessor methods typically contain very little code, inlining them can make the native code smaller and can make it execute faster.

      2.The JIT compiler does not inline property methods when debugging code because inlined code is harder to debug.

      This means that the performance of accessing a property can be fast in a release build and slow in a debug build.

      Field access is fast in both debug and release builds.

    相关知识:

    Inlining is when the code for a method (or accessor method, in this case) is compiled directly in the method that is making the call.

    This removes the overhead associated with making a call at run time at the expense of making the compiled method’s code bigger.

    4.Property Accessor Accessibility

    it is desired to have one accessibility for a get accessor method and a different accessibility for a set accessor method.

    The most common scenario is to have a public get accessor and a protected set accessor.

    how to use it?

      When defining a property with accessor methods that have different accessibilities,

      C# syntax requires that the property itself must be declared with the least-restrictive accessibility

        more restrictive accessibility be applied to just one of the accessor methods.

      In the example bottom, the property is public, and the set accessor is protected (more restrictive than public).

    示例:

      

      the Name property is itself declared as a public property,and this means that the get accessor method will be public and therefore callable by all code.

      the set accessor is declared as protected and will be callable only from code defined within SomeType or from code in a class that is derived from SomeType.

    5.Generic Property Accessor Methods

      question:why properties cannot introduce their own generic type parameters?

      answer:

      they don’t make sense conceptually.

      A property is supposed to represent a characteristic of an object that can be queried or set. Introducing a generic type parameter would mean that the behavior of the querying/setting could be changed, but conceptually, a property is not supposed to have behavior.

      If you want your object to expose some behavior—generic or not—define a method, not a property.

  • 相关阅读:
    求解奖学金问题--贪心
    装饰模式(Decorator Pattern)
    组合模式(Composite Pattern)
    Java基础:容器
    DatabaseMetaData类
    Java命名规范
    MyEclipse快捷键
    工厂模式(Factory)
    单例模式详解以及需要注意的地方(Singleton)
    SpringBoot启动流程与源码
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/5681078.html
Copyright © 2020-2023  润新知