public void PrintName(string FirstName, string LastName) {
Console.WriteLine("{0} {1}", FirstName, LastName);
}
}
Here, the PrintName()
method is overloaded — once with no parameter and again with two input parameters. Notice that the second PrintName()
method is prefixed with the Obsolete
attribute:
[Obsolete("This method is obsolete. Please use PrintName()")]
That basically marks the method as one that is not recommended for use. The class will still compile, but when you try to use this method, a warning will appear (see Figure 4-7).
Figure 4-7
The Obsolete
attribute is overloaded — if you pass in true
for the second parameter, the message set in the first parameter will be displayed as an error (by default the message is displayed as a warning):
[Obsolete("This method is obsolete. Please use PrintName()", true)]
Figure 4-8 shows the error message displayed when you use the PrintName()
method marked with the Obsolete
attribute with the second parameter set to true
.
Figure 4-8
Attributes can also be applied to a class. In the following example, the Obsolete
attribute is applied to the Contact
class:
[Obsolete("This class is obsolete. Please use NewContact")]
class Contact {
//...
}
Custom Attributes
You can also define your own custom attributes. To do so, you just need to define a class that inherits directly from System.Attribute
. The following Programmer
class is one example of a custom attribute:
public class Programmer : System.Attribute {
private string _Name;
public double Version;
public string Dept { get; set; }
public Programmer(string Name) {
this._Name = Name;
}
}
In this attribute, there are:
□ One private member ( _Name
)
□ One public member ( Version
)
□ One constructor, which takes in one string argument
Here's how to apply the Programmer
attribute to a class:
[Programmer("Wei-Meng Lee", Dept="IT", Version=1.5)]
class Contact {
//...
}
You can also apply the Programmer
attribute to methods (as the following code shows), properties, structure, and so on:
[Programmer("Wei-Meng Lee", Dept="IT", Version=1.5)]
class Contact {
[Programmer("Jason", Dept = "CS", Version = 1.6)]
public void PrintName() {
Console.WriteLine("{0} {1}", this.FirstName, this.LastName);
}
//...
}
Use the AttributeUsage
attribute to restrict the use of any attribute to certain types:
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Method |
System.AttributeTargets.Property)]
public class Programmer : System.Attribute {
private string _Name;
public double Version;
public string Dept { get; set; }
public Programmer(string Name) {
this._Name = Name;
}
}
In this example, the Programmer
attribute can only be used on class definitions, methods, and properties.
An alternative to using classes is to use a struct (for structure). A struct is a lightweight user-defined type that is very similar to a class, but with some exceptions:
□ Structs do not support inheritance or destructors.
□ A struct is a value type (class is a reference type).
□ A struct cannot declare a default constructor.
Structs implicitly derive from object
and unlike classes, a struct is a value type. This means that when an object is created from a struct and assigned to another variable, the variable will contain a copy of the struct object.
Like classes, structs support constructor, properties, and methods. The following code shows the definition for the Coordinate
struct:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
}
}
public struct Coordinate {
public double latitude { get; set; }
public double longitude { get; set; }
}
The Coordinate
struct contains two properties (defined using the automatic properties feature). You can add a constructor to the struct if you want:
public struct Coordinate {
public double latitude { get; set; }
public double longitude { get; set; }
public Coordinate(double lat, double lng) {
latitude = lat;
longitude = lng;
}
}
Remember, a struct cannot have a default constructor.
Note that the compiler will complain with the message "Backing field for automatically implemented property 'Coordinate.latitude' must be fully assigned before control is returned to the caller" when you try to compile this application. This restriction applies only to structs (classes won't have this problem). To resolve this, you need to call the default constructor of the struct, like this:
public struct Coordinate {
public double latitude { get; set; }
public double longitude { get; set; }
public Coordinate(double lat, double lng) :
this() {
latitude = lat;
longitude = lng;
}
}
You can also add methods to a struct. The following shows the ToString()
method defined in the Coordinate
struct:
public struct Coordinate {
public double latitude { get; set; }
public double longitude { get; set; }
public Coordinate(double lat, double lng) :
this() {
latitude = lat;
longitude = lng;
}
public override string ToString() {
return latitude + "," + longitude;
}
}
To use the Coordinate
struct, create a new instance using the new
keyword and then initialize its individual properties:
Читать дальше