Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "Effective C# 50 Specific Way to Improve Your C# Item 22, 23."— Presentation transcript:

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

2 Agenda Item 22: Define Outgoing Interfaces with Events Item 22: Define Outgoing Interfaces with Events Item 23: Avoid Returning References to Internal Class Objects Item 23: Avoid Returning References to Internal Class Objects

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

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

5 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; }

6 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( ) { }

7 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

8 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)); }

9 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); }

10 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 ); }

11 Event notification Events notify any number of interested clients that something happened 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 The Logger class does not need any prior knowledge of which objects are interested in logging events

12 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; }

13 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 ); }

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

15 Summary Define outgoing interfaces in classes with events: 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 Use Event HandlerList collection to manage a large number of events

16 Item 23: Avoid Returning References to Internal Class Objects Item 23: Avoid Returning References to Internal Class Objects

17 Does read-only property always work? No! No! – It may be broken by reference type function return

18 Example public 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.

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

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

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

22 Interfaces By exposing the functionality through interfaces By exposing the functionality through interfaces – Exposing the IListsource interface pointer in the DataSet Minimize the possibility that your internal data changes Minimize the possibility that your internal data changes

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" ] );

24 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" ] );

25 Take care on return value type Use the IList interface with any collection. it's not specific to the DataSet. 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 You should not simply return the DataView object which users could easily enable the editing and add/delete capability again

26 Summary Exposing reference types through your public interface allows users of your object to modify its internals 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 Limit that access by exposing private internal data using interfaces, or wrapper objects


Download ppt "Effective C# 50 Specific Way to Improve Your C# Item 22, 23."

Similar presentations


Ads by Google