달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2017. 8. 1. 13:36

Programming guide - Enumeration Types 프로그래밍/C#2017. 8. 1. 13:36


  1. Enumeration Types




https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types




Enumeration Types


An enumeration type (also named an enumeration or an enum) provides an efficient way to define a set of named integral constants that may be assigned to a variable. For example, assume that you have to define a variable whose value will represent a day of the week. There are only seven meaningful values which that variable will ever store. To define those values, you can use an enumeration type, which is declared by using the enum keyword.

C#
enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
enum Months : byte { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }; 

By default the underlying type of each element in the enum is int. You can specify another integral numeric type by using a colon, as shown in the previous example. For a full list of possible types, see enum (C# Reference).

You can verify the underlying numeric values by casting to the underlying type, as the following example shows.

C#
Days today = Days.Monday;  
int dayNumber =(int)today;  
Console.WriteLine("{0} is day number #{1}.", today, dayNumber);  

Months thisMonth = Months.Dec;  
byte monthNumber = (byte)thisMonth;  
Console.WriteLine("{0} is month number #{1}.", thisMonth, monthNumber);  

// Output:  
// Monday is day number #1.  
// Dec is month number #11.  

The following are advantages of using an enum instead of a numeric type:

  • You clearly specify for client code which values are valid for the variable.

  • In Visual Studio, IntelliSense lists the defined values.

When you do not specify values for the elements in the enumerator list, the values are automatically incremented by 1. In the previous example, Days.Sunday has a value of 0, Days.Monday has a value of 1, and so on. When you create a new Days object, it will have a default value of Days.Sunday (0) if you do not explicitly assign it a value. When you create an enum, select the most logical default value and give it a value of zero. That will cause all enums to have that default value if they are not explicitly assigned a value when they are created.

If the variable meetingDay is of type Days, then (without an explicit cast) you can only assign it one of the values defined by Days. And if the meeting day changes, you can assign a new value from Days to meetingDay:

C#
Days meetingDay = Days.Monday;
//...
meetingDay = Days.Friday;
Note

It is possible to assign any arbitrary integer value to meetingDay. For example, this line of code does not produce an error: meetingDay = (Days) 42. However, you should not do this because the implicit expectation is that an enum variable will only hold one of the values defined by the enum. To assign an arbitrary value to a variable of an enumeration type is to introduce a high risk for errors.

You can assign any values to the elements in the enumerator list of an enumeration type, and you can also use computed values:

C#
enum MachineState
{
    PowerOff = 0,
    Running = 5,
    Sleeping = 10,
    Hibernating = Sleeping + 5
}

Enumeration Types as Bit Flags

You can use an enumeration type to define bit flags, which enables an instance of the enumeration type to store any combination of the values that are defined in the enumerator list. (Of course, some combinations may not be meaningful or allowed in your program code.)

You create a bit flags enum by applying the System.FlagsAttribute attribute and defining the values appropriately so that AND, OR, NOT and XOR bitwise operations can be performed on them. In a bit flags enum, include a named constant with a value of zero that means "no flags are set." Do not give a flag a value of zero if it does not mean "no flags are set".

In the following example, another version of the Days enum, which is named Days2, is defined. Days2 has the Flags attribute and each value is assigned the next greater power of 2. This enables you to create a Days2variable whose value is Days2.Tuesday and Days2.Thursday.

C#
[Flags]
enum Days2
{
    None = 0x0,
    Sunday = 0x1,
    Monday = 0x2,
    Tuesday = 0x4,
    Wednesday = 0x8,
    Thursday = 0x10,
    Friday = 0x20,
    Saturday = 0x40
}
class MyClass
{
    Days2 meetingDays = Days2.Tuesday | Days2.Thursday;
}

To set a flag on an enum, use the bitwise OR operator as shown in the following example:

C#
// Initialize with two flags using bitwise OR.
meetingDays = Days2.Tuesday | Days2.Thursday;

// Set an additional flag using bitwise OR.
meetingDays = meetingDays | Days2.Friday;

Console.WriteLine("Meeting days are {0}", meetingDays);
// Output: Meeting days are Tuesday, Thursday, Friday

// Remove a flag using bitwise XOR.
meetingDays = meetingDays ^ Days2.Tuesday;
Console.WriteLine("Meeting days are {0}", meetingDays);
// Output: Meeting days are Thursday, Friday

To determine whether a specific flag is set, use a bitwise AND operation, as shown in the following example:

C#
// Test value of flags using bitwise AND.
bool test = (meetingDays & Days2.Thursday) == Days2.Thursday;
Console.WriteLine("Thursday {0} a meeting day.", test == true ? "is" : "is not");
// Output: Thursday is a meeting day.

For more information about what to consider when you define enumeration types with the System.FlagsAttributeattribute, see System.Enum.

Using the System.Enum Methods to Discover and Manipulate Enum Values

All enums are instances of the System.Enum type. You cannot derive new classes from System.Enum, but you can use its methods to discover information about and manipulate values in an enum instance.

C#
string s = Enum.GetName(typeof(Days), 4);
Console.WriteLine(s);

Console.WriteLine("The values of the Days Enum are:");
foreach (int i in Enum.GetValues(typeof(Days)))
    Console.WriteLine(i);

Console.WriteLine("The names of the Days Enum are:");
foreach (string str in Enum.GetNames(typeof(Days)))
    Console.WriteLine(str);

For more information, see System.Enum.

You can also create a new method for an enum by using an extension method. For more information, see How to: Create a New Method for an Enumeration.











:
Posted by 지훈2
2017. 7. 5. 07:17

ConfigurationManager Class 프로그래밍/C#2017. 7. 5. 07:17


  1. ConfigurationManager Class




ConfigurationManager Class


https://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager(v=vs.110).aspx


Provides access to configuration files for client applications. This class cannot be inherited.

Namespace:   System.Configuration
Assembly:  System.Configuration (in System.Configuration.dll)

Inheritance Hierarchy

System.Object
  System.Configuration.ConfigurationManager

Syntax

public static class ConfigurationManager

Properties

NameDescription
System_CAPS_pubpropertySystem_CAPS_staticAppSettings

Gets the AppSettingsSection data for the current application's default configuration.

System_CAPS_pubpropertySystem_CAPS_staticConnectionStrings

Gets the ConnectionStringsSection data for the current application's default configuration.

Methods

NameDescription
System_CAPS_pubmethodSystem_CAPS_staticGetSection(String)

Retrieves a specified configuration section for the current application's default configuration.

System_CAPS_pubmethodSystem_CAPS_staticOpenExeConfiguration(ConfigurationUserLevel)

Opens the configuration file for the current application as a Configurationobject.

System_CAPS_pubmethodSystem_CAPS_staticOpenExeConfiguration(String)

Opens the specified client configuration file as a Configuration object.

System_CAPS_pubmethodSystem_CAPS_staticOpenMachineConfiguration()

Opens the machine configuration file on the current computer as a Configuration object.

System_CAPS_pubmethodSystem_CAPS_staticOpenMappedExeConfiguration(ExeConfigurationFileMap, ConfigurationUserLevel)

Opens the specified client configuration file as a Configuration object that uses the specified file mapping and user level.

System_CAPS_pubmethodSystem_CAPS_staticOpenMappedExeConfiguration(ExeConfigurationFileMap, ConfigurationUserLevel, Boolean)

Opens the specified client configuration file as a Configuration object that uses the specified file mapping, user level, and preload option.

System_CAPS_pubmethodSystem_CAPS_staticOpenMappedMachineConfiguration(ConfigurationFileMap)

Opens the machine configuration file as a Configuration object that uses the specified file mapping.

System_CAPS_pubmethodSystem_CAPS_staticRefreshSection(String)

Refreshes the named section so the next time that it is retrieved it will be re-read from disk.

Remarks

The ConfigurationManager class enables you to access machine, application, and user configuration information. This class replaces the ConfigurationSettings class, which is deprecated. For web applications, use the WebConfigurationManager class.

To use the ConfigurationManager class, your project must reference the System.Configuration assembly. By default, some project templates, like Console Application, do not reference this assembly so you must manually reference it.

System_CAPS_noteNote

The name and location of the application configuration file depend on the application's host. For more information, see NIB: Application Configuration Files.

You can use the built-in System.Configuration types or derive from them to handle configuration information. By using these types, you can work directly with configuration information and you can extend configuration files to include custom information.

The ConfigurationManager class includes members that enable you to perform the following tasks:

  • Read a section from a configuration file. To access configuration information, call the GetSection method. For some sections such as appSettings and connectionStrings, use the AppSettings and ConnectionStrings classes. These members perform read-only operations, use a single cached instance of the configuration, and are multithread aware.

  • Read and write configuration files as a whole. Your application can read and write configuration settings at any level, for itself or for other applications or computers, locally or remotely. Use one of the methods provided by the ConfigurationManager class to open a configuration file such as SampleApp.exe.config. These methods return a Configuration object that in turn exposes methods and properties you can use to work with the associated configuration files. The methods perform read or write operations and create the configuration data every time that a file is written.

  • Support configuration tasks. The following types are used to support various configuration tasks:

    In addition to working with existing configuration information, you can create and work with custom configuration elements by extending the built-in configuration types such as the ConfigurationElementConfigurationElementCollectionConfigurationProperty, and ConfigurationSection classes. For an example of how to extend a built-in configuration type programmatically, see ConfigurationSection. For an example of how to extend a built-in configuration type that uses the attribute-based model, see ConfigurationElement.

Notes to Implementers:

The Configuration class enables programmatic access for editing configuration files. You use one of the Open methods provided by ConfigurationManager. These methods return a Configuration object, which in turn provides the required methods and properties to handle the underlying configuration files. You can access these files for reading or writing.

To read the configuration files, use GetSection or GetSectionGroup to read configuration information. The user or process that reads must have the following permissions:

  • Read permission on the configuration file at the current configuration hierarchy level.

  • Read permissions on all the parent configuration files.

If your application needs read-only access to its own configuration, we recommend that you use the GetSection method. This method provides access to the cached configuration values for the current application, which has better performance than the Configuration class.

To write to the configuration files, use one of the Save methods. The user or process that writes must have the following permissions:

  • Write permission on the configuration file and directory at the current configuration hierarchy level.

  • Read permissions on all the configuration files.

Examples

The first example shows a simple console application that reads application settings, adds a new setting, and updates an existing setting.

using System;
using System.Configuration;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ReadAllSettings();
            ReadSetting("Setting1");
            ReadSetting("NotValid");
            AddUpdateAppSettings("NewSetting", "May 7, 2014");
            AddUpdateAppSettings("Setting1", "May 8, 2014");
            ReadAllSettings();
        }

        static void ReadAllSettings()
        {
            try
            {
                var appSettings = ConfigurationManager.AppSettings;

                if (appSettings.Count == 0)
                {
                    Console.WriteLine("AppSettings is empty.");
                }
                else
                {
                    foreach (var key in appSettings.AllKeys)
                    {
                        Console.WriteLine("Key: {0} Value: {1}", key, appSettings[key]);
                    }
                }
            }
            catch (ConfigurationErrorsException)
            {
                Console.WriteLine("Error reading app settings");
            }
        }

        static void ReadSetting(string key)
        {
            try
            {
                var appSettings = ConfigurationManager.AppSettings;
                string result = appSettings[key] ?? "Not Found";
                Console.WriteLine(result);
            }
            catch (ConfigurationErrorsException)
            {
                Console.WriteLine("Error reading app settings");
            }
        }

        static void AddUpdateAppSettings(string key, string value)
        {
            try
            {
                var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                var settings = configFile.AppSettings.Settings;
                if (settings[key] == null)
                {
                    settings.Add(key, value);
                }
                else
                {
                    settings[key].Value = value;
                }
                configFile.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
            }
            catch (ConfigurationErrorsException)
            {
                Console.WriteLine("Error writing app settings");
            }
        }
    }
}

The previous example assumes your project has an App.config file as shown below.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="Setting1" value="May 5, 2014"/>
    <add key="Setting2" value="May 6, 2014"/>
  </appSettings>
</configuration>

The following example shows how to use a connection string to read data from a database.

using System;
using System.Configuration;
using System.Data.SqlClient;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ReadProducts();
        }

        static void ReadProducts()
        {
            var connectionString = ConfigurationManager.ConnectionStrings["WingtipToys"].ConnectionString;
            string queryString = "SELECT Id, ProductName FROM dbo.Products;";
            using (var connection = new SqlConnection(connectionString))
            {
                var command = new SqlCommand(queryString, connection);
                connection.Open();
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
                    }
                }
            }
        }
    }
}

The previous example assumes your project has an App.config as shown below.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <connectionStrings>
      <add name="WingtipToys" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=WingtipToys;Integrated Security=True;Pooling=False" />
    </connectionStrings>
</configuration>












:
Posted by 지훈2
2017. 6. 18. 05:12

C# Programming Guide - Delegates 프로그래밍/C#2017. 6. 18. 05:12


  1. Delegates
  2. Using Delegates
  3. Delegates with Named vs. Anonymous Methods
  4. How to: Combine Delegates (Multicast Delegates)
  5. How to: Declare, Instantiate, and Use a Delegate



https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/



Delegates


delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates. You create a custom method, and a class such as a windows control can call your method when a certain event occurs. The following example shows a delegate declaration:

C#
public delegate int PerformCalculation(int x, int y);

Any method from any accessible class or struct that matches the delegate type can be assigned to the delegate. The method can be either static or an instance method. This makes it possible to programmatically change method calls, and also plug new code into existing classes.

Note

In the context of method overloading, the signature of a method does not include the return value. But in the context of delegates, the signature does include the return value. In other words, a method must have the same return type as the delegate.

This ability to refer to a method as a parameter makes delegates ideal for defining callback methods. For example, a reference to a method that compares two objects could be passed as an argument to a sort algorithm. Because the comparison code is in a separate procedure, the sort algorithm can be written in a more general way.

Delegates Overview

Delegates have the following properties:

  • Delegates are like C++ function pointers but are type safe.

  • Delegates allow methods to be passed as parameters.

  • Delegates can be used to define callback methods.

  • Delegates can be chained together; for example, multiple methods can be called on a single event.

  • Methods do not have to match the delegate type exactly. For more information, see Using Variance in Delegates.

  • C# version 2.0 introduced the concept of Anonymous Methods, which allow code blocks to be passed as parameters in place of a separately defined method. C# 3.0 introduced lambda expressions as a more concise way of writing inline code blocks. Both anonymous methods and lambda expressions (in certain contexts) are compiled to delegate types. Together, these features are now known as anonymous functions. For more information about lambda expressions, see Anonymous Functions.

In This Section

C# Language Specification

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

Delegates, Events, and Lambda Expressions in C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

Delegates and Events in Learning C# 3.0: Master the fundamentals of C# 3.0

See Also

Delegate
C# Programming Guide
Events






Using Delegates


delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. Unlike C function pointers, delegates are object-oriented, type safe, and secure. The type of a delegate is defined by the name of the delegate. The following example declares a delegate named Del that can encapsulate a method that takes a string as an argument and returns void:

C#
public delegate void Del(string message);

A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an anonymous Method. Once a delegate is instantiated, a method call made to the delegate will be passed by the delegate to that method. The parameters passed to the delegate by the caller are passed to the method, and the return value, if any, from the method is returned to the caller by the delegate. This is known as invoking the delegate. An instantiated delegate can be invoked as if it were the wrapped method itself. For example:

C#
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
    System.Console.WriteLine(message);
}
C#
// Instantiate the delegate.
Del handler = DelegateMethod;

// Call the delegate.
handler("Hello World");

Delegate types are derived from the Delegate class in the .NET Framework. Delegate types are sealed—they cannot be derived from— and it is not possible to derive custom classes from Delegate. Because the instantiated delegate is an object, it can be passed as a parameter, or assigned to a property. This allows a method to accept a delegate as a parameter, and call the delegate at some later time. This is known as an asynchronous callback, and is a common method of notifying a caller when a long process has completed. When a delegate is used in this fashion, the code using the delegate does not need any knowledge of the implementation of the method being used. The functionality is similar to the encapsulation interfaces provide.

Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. It allows the caller's code to become part of the sort algorithm. The following example method uses the Del type as a parameter:

C#
public void MethodWithCallback(int param1, int param2, Del callback)
{
    callback("The number is: " + (param1 + param2).ToString());
}

You can then pass the delegate created above to that method:

C#
MethodWithCallback(1, 2, handler);

and receive the following output to the console:

The number is: 3

Using the delegate as an abstraction, MethodWithCallback does not need to call the console directly—it does not have to be designed with a console in mind. What MethodWithCallback does is simply prepare a string and pass the string to another method. This is especially powerful since a delegated method can use any number of parameters.

When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer to any type of object as long as there is a method on that object that matches the delegate signature. When a delegate is constructed to wrap a static method, it only references the method. Consider the following declarations:

C#
public class MethodClass
{
    public void Method1(string message) { }
    public void Method2(string message) { }
}

Along with the static DelegateMethod shown previously, we now have three methods that can be wrapped by a Del instance.

A delegate can call more than one method when invoked. This is referred to as multicasting. To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). For example:

C#
MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = DelegateMethod;

//Both types of assignment are valid.
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;

At this point allMethodsDelegate contains three methods in its invocation list—Method1Method2, and DelegateMethod. The original three delegates, d1d2, and d3, remain unchanged. When allMethodsDelegate is invoked, all three methods are called in order. If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. When any of the methods throws an exception that is not caught within the method, that exception is passed to the caller of the delegate and no subsequent methods in the invocation list are called. If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. To remove a method from the invocation list, use the decrement or decrement assignment operator ('-' or '-='). For example:

C#
//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

Because delegate types are derived from System.Delegate, the methods and properties defined by that class can be called on the delegate. For example, to find the number of methods in a delegate's invocation list, you may write:

C#
int invocationCount = d1.GetInvocationList().GetLength(0);

Delegates with more than one method in their invocation list derive from MulticastDelegate, which is a subclass of System.Delegate. The above code works in either case because both classes support GetInvocationList.

Multicast delegates are used extensively in event handling. Event source objects send event notifications to recipient objects that have registered to receive that event. To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. The source calls the delegate when the event occurs. The delegate then calls the event handling method on the recipient, delivering the event data. The delegate type for a given event is defined by the event source. For more, see Events.

Comparing delegates of two different types assigned at compile-time will result in a compilation error. If the delegate instances are statically of the type System.Delegate, then the comparison is allowed, but will return false at run time. For example:

C#
delegate void Delegate1();
delegate void Delegate2();

static void method(Delegate1 d, Delegate2 e, System.Delegate f)
{
    // Compile-time error.
    //Console.WriteLine(d == e);

    // OK at compile-time. False if the run-time type of f 
    // is not the same as that of d.
    System.Console.WriteLine(d == f);
}

See Also

C# Programming Guide
Delegates
Using Variance in Delegates
Variance in Delegates
Using Variance for Func and Action Generic Delegates
Events






Delegates with Named vs. Anonymous Methods


A delegate can be associated with a named method. When you instantiate a delegate by using a named method, the method is passed as a parameter, for example:

C#
// Declare a delegate:
delegate void Del(int x);

// Define a named method:
void DoWork(int k) { /* ... */ }

// Instantiate the delegate using the method as a parameter:
Del d = obj.DoWork;

This is called using a named method. Delegates constructed with a named method can encapsulate either a staticmethod or an instance method. Named methods are the only way to instantiate a delegate in earlier versions of C#. However, in a situation where creating a new method is unwanted overhead, C# enables you to instantiate a delegate and immediately specify a code block that the delegate will process when it is called. The block can contain either a lambda expression or an anonymous method. For more information, see Anonymous Functions.

Remarks

The method that you pass as a delegate parameter must have the same signature as the delegate declaration.

A delegate instance may encapsulate either static or instance method.2

Although the delegate can use an out parameter, we do not recommend its use with multicast event delegates because you cannot know which delegate will be called.

Example 1

The following is a simple example of declaring and using a delegate. Notice that both the delegate, Del, and the associated method, MultiplyNumbers, have the same signature

C#
// Declare a delegate
delegate void Del(int i, double j);

class MathClass
{
    static void Main()
    {
        MathClass m = new MathClass();

        // Delegate instantiation using "MultiplyNumbers"
        Del d = m.MultiplyNumbers;

        // Invoke the delegate object.
        System.Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':");
        for (int i = 1; i <= 5; i++)
        {
            d(i, 2);
        }

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    // Declare the associated method.
    void MultiplyNumbers(int m, double n)
    {
        System.Console.Write(m * n + " ");
    }
}
/* Output:
    Invoking the delegate using 'MultiplyNumbers':
    2 4 6 8 10
*/

Example 2

In the following example, one delegate is mapped to both static and instance methods and returns specific information from each.

C#
// Declare a delegate
delegate void Del();

class SampleClass
{
    public void InstanceMethod()
    {
        System.Console.WriteLine("A message from the instance method.");
    }

    static public void StaticMethod()
    {
        System.Console.WriteLine("A message from the static method.");
    }
}

class TestSampleClass
{
    static void Main()
    {
        SampleClass sc = new SampleClass();

        // Map the delegate to the instance method:
        Del d = sc.InstanceMethod;
        d();

        // Map to the static method:
        d = SampleClass.StaticMethod;
        d();
    }
}
/* Output:
    A message from the instance method.
    A message from the static method.
*/






How to: Combine Delegates (Multicast Delegates)


This example demonstrates how to create multicast delegates. A useful property of delegate objects is that multiple objects can be assigned to one delegate instance by using the + operator. The multicast delegate contains a list of the assigned delegates. When the multicast delegate is called, it invokes the delegates in the list, in order. Only delegates of the same type can be combined.

The - operator can be used to remove a component delegate from a multicast delegate.

Example

C#
using System;

// Define a custom delegate that has a string parameter and returns void.
delegate void CustomDel(string s);

class TestClass
{
    // Define two methods that have the same signature as CustomDel.
    static void Hello(string s)
    {
        System.Console.WriteLine("  Hello, {0}!", s);
    }

    static void Goodbye(string s)
    {
        System.Console.WriteLine("  Goodbye, {0}!", s);
    }

    static void Main()
    {
        // Declare instances of the custom delegate.
        CustomDel hiDel, byeDel, multiDel, multiMinusHiDel;

        // In this example, you can omit the custom delegate if you 
        // want to and use Action<string> instead.
        //Action<string> hiDel, byeDel, multiDel, multiMinusHiDel;

        // Create the delegate object hiDel that references the
        // method Hello.
        hiDel = Hello;

        // Create the delegate object byeDel that references the
        // method Goodbye.
        byeDel = Goodbye;

        // The two delegates, hiDel and byeDel, are combined to 
        // form multiDel. 
        multiDel = hiDel + byeDel;

        // Remove hiDel from the multicast delegate, leaving byeDel,
        // which calls only the method Goodbye.
        multiMinusHiDel = multiDel - hiDel;

        Console.WriteLine("Invoking delegate hiDel:");
        hiDel("A");
        Console.WriteLine("Invoking delegate byeDel:");
        byeDel("B");
        Console.WriteLine("Invoking delegate multiDel:");
        multiDel("C");
        Console.WriteLine("Invoking delegate multiMinusHiDel:");
        multiMinusHiDel("D");
    }
}
/* Output:
Invoking delegate hiDel:
  Hello, A!
Invoking delegate byeDel:
  Goodbye, B!
Invoking delegate multiDel:
  Hello, C!
  Goodbye, C!
Invoking delegate multiMinusHiDel:
  Goodbye, D!
*/






How to: Declare, Instantiate, and Use a Delegate


In C# 1.0 and later, delegates can be declared as shown in the following example.

C#
// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
    Console.WriteLine("Notification received for: {0}", name);
}
C#
// Create an instance of the delegate.
Del del1 = new Del(Notify);

C# 2.0 provides a simpler way to write the previous declaration, as shown in the following example.

C#
// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

In C# 2.0 and later, it is also possible to use an anonymous method to declare and initialize a delegate, as shown in the following example.

C#
// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name)
    { Console.WriteLine("Notification received for: {0}", name); };

In C# 3.0 and later, delegates can also be declared and instantiated by using a lambda expression, as shown in the following example.

C#
// Instantiate Del by using a lambda expression.
Del del4 = name =>  { Console.WriteLine("Notification received for: {0}", name); };

For more information, see Lambda Expressions.

The following example illustrates declaring, instantiating, and using a delegate. The BookDB class encapsulates a bookstore database that maintains a database of books. It exposes a method, ProcessPaperbackBooks, which finds all paperback books in the database and calls a delegate for each one. The delegate type that is used is named ProcessBookDelegate. The Test class uses this class to print the titles and average price of the paperback books.

The use of delegates promotes good separation of functionality between the bookstore database and the client code. The client code has no knowledge of how the books are stored or how the bookstore code finds paperback books. The bookstore code has no knowledge of what processing is performed on the paperback books after it finds them.

Example

C#
// A set of classes for handling a bookstore:
namespace Bookstore
{
    using System.Collections;

    // Describes a book in the book list:
    public struct Book
    {
        public string Title;        // Title of the book.
        public string Author;       // Author of the book.
        public decimal Price;       // Price of the book.
        public bool Paperback;      // Is it paperback?

        public Book(string title, string author, decimal price, bool paperBack)
        {
            Title = title;
            Author = author;
            Price = price;
            Paperback = paperBack;
        }
    }

    // Declare a delegate type for processing a book:
    public delegate void ProcessBookDelegate(Book book);

    // Maintains a book database.
    public class BookDB
    {
        // List of all books in the database:
        ArrayList list = new ArrayList();

        // Add a book to the database:
        public void AddBook(string title, string author, decimal price, bool paperBack)
        {
            list.Add(new Book(title, author, price, paperBack));
        }

        // Call a passed-in delegate on each paperback book to process it: 
        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
        {
            foreach (Book b in list)
            {
                if (b.Paperback)
                    // Calling the delegate:
                    processBook(b);
            }
        }
    }
}


// Using the Bookstore classes:
namespace BookTestClient
{
    using Bookstore;

    // Class to total and average prices of books:
    class PriceTotaller
    {
        int countBooks = 0;
        decimal priceBooks = 0.0m;

        internal void AddBookToTotal(Book book)
        {
            countBooks += 1;
            priceBooks += book.Price;
        }

        internal decimal AveragePrice()
        {
            return priceBooks / countBooks;
        }
    }

    // Class to test the book database:
    class TestBookDB
    {
        // Print the title of the book.
        static void PrintTitle(Book b)
        {
            System.Console.WriteLine("   {0}", b.Title);
        }

        // Execution starts here.
        static void Main()
        {
            BookDB bookDB = new BookDB();

            // Initialize the database with some books:
            AddBooks(bookDB);

            // Print all the titles of paperbacks:
            System.Console.WriteLine("Paperback Book Titles:");

            // Create a new delegate object associated with the static 
            // method Test.PrintTitle:
            bookDB.ProcessPaperbackBooks(PrintTitle);

            // Get the average price of a paperback by using
            // a PriceTotaller object:
            PriceTotaller totaller = new PriceTotaller();

            // Create a new delegate object associated with the nonstatic 
            // method AddBookToTotal on the object totaller:
            bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

            System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",
                    totaller.AveragePrice());
        }

        // Initialize the book database with some test books:
        static void AddBooks(BookDB bookDB)
        {
            bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
            bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true);
            bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false);
            bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true);
        }
    }
}
/* Output:
Paperback Book Titles:
   The C Programming Language
   The Unicode Standard 2.0
   Dogbert's Clues for the Clueless
Average Paperback Book Price: $23.97
*/

Robust Programming

  • Declaring a delegate.

    The following statement declares a new delegate type.

    C#
    public delegate void ProcessBookDelegate(Book book);
    

    Each delegate type describes the number and types of the arguments, and the type of the return value of methods that it can encapsulate. Whenever a new set of argument types or return value type is needed, a new delegate type must be declared.

  • Instantiating a delegate.

    After a delegate type has been declared, a delegate object must be created and associated with a particular method. In the previous example, you do this by passing the PrintTitle method to the ProcessPaperbackBooks method as in the following example:

    C#
    bookDB.ProcessPaperbackBooks(PrintTitle);
    

    This creates a new delegate object associated with the static method Test.PrintTitle. Similarly, the non-static method AddBookToTotal on the object totaller is passed as in the following example:

    C#
    bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
    

    In both cases a new delegate object is passed to the ProcessPaperbackBooks method.

    After a delegate is created, the method it is associated with never changes; delegate objects are immutable.

  • Calling a delegate.

    After a delegate object is created, the delegate object is typically passed to other code that will call the delegate. A delegate object is called by using the name of the delegate object, followed by the parenthesized arguments to be passed to the delegate. Following is an example of a delegate call:

    C#
    processBook(b);
    

    A delegate can be either called synchronously, as in this example, or asynchronously by using BeginInvoke and EndInvoke methods.




:
Posted by 지훈2