effective c# 50 specific way to improve your c# item 22, 23

26
Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Upload: irma-paul

Post on 18-Jan-2018

221 views

Category:

Documents


0 download

DESCRIPTION

Item 22: Define Outgoing Interfaces with Events Item 22: Define Outgoing Interfaces with Events

TRANSCRIPT

Page 1: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Effective C#50 Specific Way to Improve Your C#

Item 22, 23

Page 2: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Agenda

• Item 22: Define Outgoing Interfaces with Events

• Item 23: Avoid Returning References to Internal Class Objects

Page 3: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

• Item 22: Define Outgoing Interfaces with Events

Page 4: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Events and Delegates

• Events and delegates are the same things?– No, you can use delegates without defining events

Page 5: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Sample log class (1/3)

public class LoggerEventArgs : EventArgs{ public readonly string Message; public readonly int Priority; public LoggerEventArgs ( int p, string m ) { Priority = p; Message = m; }}

Page 6: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Sample log class (2/3)

// Define the signature for the event handler:public delegate void AddMessageEventHandler( object sender, LoggerEventArgs msg );

public class Logger{ static Logger( ) { _theOnly = new Logger( ); }

private Logger( ) { }

Page 7: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Sample log class (3/3) private static Logger _theOnly = null; public Logger Singleton { get { return _theOnly; } }

// Define the event: public event AddMessageEventHandler Log;

// add a message, and log it. public void AddMsg ( int priority, string msg ) { // This idiom discussed below. AddMessageEventHandler l = Log; if ( l != null ) l ( null, new LoggerEventArgs( priority, msg ) ); }}

Reference copy

Page 8: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

public event field public class Logger{ private AddMessageEventHandler _Log;

public event AddMessageEventHandler Log { add { _Log = _Log + value; } remove { _Log = _Log - value; } }

public void AddMsg (int priority, string msg) { AddMessageEventHandler l = _Log; if (l != null) l (null, new LoggerEventArgs (priority, msg)); } }}

Page 9: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

A Class directs output to the console

class ConsoleLogger{

static ConsoleLogger(){

Logger.Log += new AddMessageEventHandler(Logger_Log);}private static void Logger_Log(object sender, LoggerEventArgs msg){

Console.Error.WriteLine("{0}:\t{1}",msg.Priority.ToString(),msg.Message);

}}

Page 10: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

A Class directs output to the system event log

class EventLogger{ private static string eventSource; private static EventLog logDest;

static EventLogger() { logger.Log +=new AddMessageEventHandler( Event_Log ); }

public static string EventSource { get { return eventSource; }

set { eventSource = value; if ( ! EventLog.SourceExists( eventSource ) ) EventLog.CreateEventSource( eventSource, "ApplicationEventLogger" );

if ( logDest != null ) logDest.Dispose( ); logDest = new EventLog( ); logDest.Source = eventSource; } }

private static void Event_Log( object sender, LoggerEventArgs msg ) { if ( logDest != null ) logDest.WriteEntry( msg.Message, EventLogEntryType.Information, msg.Priority ); }}

Page 11: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Event notification

• Events notify any number of interested clients that something happened

• The Logger class does not need any prior knowledge of which objects are interested in logging events

Page 12: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

The extended Logger class (1/2)

public class Logger{ private static System.ComponentModel.EventHandlerList Handlers = new System.ComponentModel.EventHandlerList();

static public void AddLogger(string system, AddMessageEventHandler ev ) { Handlers[ system ] = ev; }

static public void RemoveLogger( string system ) { Handlers[ system ] = null; }

Page 13: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

The extended Logger class (2/2) static public void AddMsg ( string system, int priority, string msg ) { if ( ( system != null ) && ( system.Length > 0 ) ) { AddMessageEventHandler l = Handlers[ system ] as AddMessageEventHandler;

LoggerEventArgs args = new LoggerEventArgs( priority, msg ); if ( l != null ) l ( null, args );

// The empty string means receive all messages: l = Handlers[ "" ] as AddMessageEventHandler; if ( l != null ) l( null, args ); } }}

Page 14: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Event HandlerList collection

• A class that contains a large number of events in its interface– consider using this collection of event handlers

Page 15: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Summary

• Define outgoing interfaces in classes with events: – Any number of clients can attach handlers to the events

and process them. – Those clients need not be known at compile time.

• Use Event HandlerList collection to manage a large number of events

Page 16: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

• Item 23: Avoid Returning References to Internal Class Objects

Page 17: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Does read-only property always work?

• No!– It may be broken by reference type function return

Page 18: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Examplepublic class MyBusinessObject{ // Read Only property providing access to a // private data member: private DataSet _ds; public DataSet Data { get { return _ds; } }}// Access the dataset:DataSet ds = bizObj.Data;

// Not intended, but allowed:ds.Tables.Clear( ); // Deletes all data tables.

Page 19: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Strategies for protecting your internal data structures• value types• immutable types• Interfaces• wrappers

Page 20: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Value types

• Any changes to the copy retrieved by the clients of your class do not affect your object's internal state

Page 21: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Immutable types

• You can return strings, or any immutable type, safely knowing that no client of your class can modify the string.

Page 22: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Interfaces

• By exposing the functionality through interfaces– Exposing the IListsource interface pointer in the DataSet

• Minimize the possibility that your internal data changes

Page 23: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Wrappers (1/2)

{ // Read Only property providing access to a // private data member: private DataSet _ds; public DataView this[ string tableName ] { get { return _ds.DefaultViewManager. CreateDataView( _ds.Tables[ tableName ] ); } }}

// Access the dataset:DataView list = bizObj[ "customers" ];foreach ( DataRowView r in list ) Console.WriteLine( r[ "name" ] );

Page 24: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Wrappers (2/2)public class MyBusinessObject{ // Read Only property providing access to a // private data member: private DataSet _ds; public IList this[ string tableName ] { get { DataView view = _ds.DefaultViewManager.CreateDataView ( _ds.Tables[ tableName ] ); view.AllowNew = false; view.AllowDelete = false; view.AllowEdit = false; return view; } }}

// Access the dataset: IList dv = bizOjb[ "customers" ]; foreach ( DataRowView r in dv ) Console.WriteLine( r[ "name" ] );

Page 25: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Take care on return value type

• Use the IList interface with any collection. it's not specific to the DataSet.

• You should not simply return the DataView object which users could easily enable the editing and add/delete capability again

Page 26: Effective C# 50 Specific Way to Improve Your C# Item 22, 23

Summary

• Exposing reference types through your public interface allows users of your object to modify its internals

• Limit that access by exposing private internal data using interfaces, or wrapper objects