1_
Create Windows Service that will just write to log
In Visual Studio 2010, create new project, Windows group, Windows service
in Service1.cs, OnStart(string[] args) {...} add an action that the service will start. The method has to return in 30 seconds.C# Debug.Listeners.Add(new TextWriterTraceListener(System.IO.File.Create(@"c:\_delete\trace.txt"))); Trace.AutoFlush = true; Trace.WriteLine("starting");Similar way implement OnStop(), OnShutdown)(), OnPause(), OnContinue() Add installer: in Solution explorer, Doubleclick on Service1.cs in Service1 designer, right click and select "Add Installer" doubleclick on ProjectInstaller.cs Right click on serviceInstaller1, select Properties, set Service Name = "MyService", Start Type="Automatic" if you want to service to start automatically Right click on serviceProcessInstaller1, select Properties, set Account = "LocalSystem" in order to avoid entering user name and password Install: InstallUtil.exe WindowsServiceBasics.exe Start: in start menu type "services.msc", find MyService, right click Start Note: you do not have to install the service again when you recompile the binary. Unistall: InstallUtil.exe /u WindowsServiceBasics.exe Note: You need to close the management console window (service is marked for deletion) Debugging: Start the service (see above) From Visual Studio (running as Administrator), menu Debug, Attach to process Click "Show processes from all users" Select process that belongs to the service, click Attach
2_
How to specify credentials for Windows service
1. Programatically:
Right click on serviceProcessInstaller1, select Properties, set Account = "myAccount"
C# // ProjectInstaller.Designer.cs private void InitializeComponents() { ... this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; this.serviceProcessInstaller1.Password = null; this.serviceProcessInstaller1.Username = null; ... }2. Configuration services.msc right click on the service tab LogOn, enter user and password
3_
Write a code that populates common members of PersonLite and Person (inherits from PersonLite) classes using generics
C# private class PersonLite { internal int Id; internal string Name; } private class Person : PersonLite { internal DateTime BirthDay; } internal static void ShowBasics() { PersonLite personLite = new PersonLite(); Populate(personLite); Person person = new Person(); Populate(person); person.BirthDay = DateTime.Parse("1969-01-01"); } private static void Populate<T>(T p) where T : PersonLite { // read data from external source, e.g. DB p.Id = 1; p.Name = "John"; }
4_
Create a generic method that returns new object of type T
C# private class PersonLite { internal int Id; internal string Name; } private class Person : PersonLite { internal DateTime BirthDay; } internal static void DemoCreateNewObject() { PersonLite personLite = CreateNew<PersonLite>(); Person person = CreateNew<Person>(); } private static T CreateNew<T>() where T : PersonLite, new() { T result = new T(); result.Name = "new"; return result; }
5_
Create list based on generic type (Person or PersonLite) passed in
C# private class PersonLite { internal int Id; internal string Name; } private class Person : PersonLite { internal DateTime BirthDay; } internal static void DemoLoadDataBasedOnType() { List<PersonLite> list = CreateList<PersonLite>(); List<Person> list2 = CreateList<Person>(); } private static List<T> CreateList<T>() where T : PersonLite, new() // new() is needed New<T>() { List<T> result = new List<T>(); Type t = typeof(T); int count = 1; switch (t.Name) { // this can be used to generate a SQL query case "PersonLite": count = 2; break; case "Person": count = 3; break; } for (int i = 0; i < count; i++) { T item = new T(); item.Name = "new"; result.Add(item); } return result; }
7_
Explain dynamic
If an object is defined as dynammic, it bypasses static type checks at compile time
C# DateTime date = new DateTime(); // date.AddCentury(1); fails at compile time dynamic dateDynamic = new DateTime(); dateDynamic.AddCentury(1); // fails at runtime var obj = date as dynamic; obj.AddCentury(); // fails at runtime
8_
Convert Enum to string and back
C# public enum Department { IT, Finance } string text = Enum.GetName(IT.GetType(), IT); Department d = (Department) Enum.Parse(typeof(Department), "IT");
9_
What are immutable classes, what is the problem, how could it be prevented?
Immutable types are reference types with value type semantics.
Problem: when a class is passed as an argument to a method, its content can be unexpectedly modified.
How to prevent that: Classes can be ensured to be immutable by using readonly keyword for their members.
Problem: when a class is passed as an argument to a method, its content can be unexpectedly modified.
How to prevent that: Classes can be ensured to be immutable by using readonly keyword for their members.
10_
How to identify assembly architecture
corflags myassembly.exe
Any CPU: PE = PE32 and 32BIT = 0 x86: PE = PE32 and 32BIT = 1 64-bit: PE = PE32+ and 32BIT = 0
11_
Private XML element for assembly reference
XML <Reference Include="myLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=..., processorArchitecture=MSIL"> <Private>True</Private> </Reference>Identifies if that the assembly file will be copied to the output (e.g. bin) folder. If not specified, build task will decide.
12_
What is mixed mode assembly
Source MSDN : Mixed assemblies are capable of containing both unmanaged machine instructions and MSIL instructions. This allows them to call and be called by .NET components, while retaining compatibility with components that are entirely unmanaged. Using mixed assemblies, developers can author applications using a mixture of managed and unmanaged functionality. This makes mixed assemblies ideal for migrating existing Visual C++ applications to the .NET Platform.
An existing application consisting entirely of unmanaged functions can be brought to the .NET platform by recompiling just one module with the /clr compiler switch
An existing application consisting entirely of unmanaged functions can be brought to the .NET platform by recompiling just one module with the /clr compiler switch
13_
How list and array get placed in LOH
List is implented using an array and when new item is added, a new and larger array is allocated
and the old one is released. List reaches 85k with about 20.000 items.
Arrays with 10,000 or more end up on LOH.
Arrays with 10,000 or more end up on LOH.
14_
Type of GC roots
Local variables: are kept alive as long as the method is on call stack (in Release build, JIT can unmark it before the method exits)
Static variables: always considered GC roots
Managed object passed to COM+ through interop: Ends when COM reference counter is set to 0.
Object with finalizer: If it is no longer live, it becomes special kind of GC root until .net called the finalizer (placed in finalizer queue). Require more than one collection GC. Object with finalizers cause delay to be released from memory, use Dispose() whenever possible and GC.SuppressFinalize().
Static variables: always considered GC roots
Managed object passed to COM+ through interop: Ends when COM reference counter is set to 0.
Object with finalizer: If it is no longer live, it becomes special kind of GC root until .net called the finalizer (placed in finalizer queue). Require more than one collection GC. Object with finalizers cause delay to be released from memory, use Dispose() whenever possible and GC.SuppressFinalize().
15_
Type of memory leaks and how to solve them
Holding references to managed objects (e.g. event handlers):
Solution:
- use local rather than global variable
- call Dispose() or use "using(...){ }" concept
- set variable to null when it is not needed anymore
Failing to release unmanaged resources
- practises of deallocating unmanaged code apply
Failing to dispose Drawing objects
e.g Bitmaps, brushes, fonts - these are managed objects, but they hold references to unmanaged objects. These resources are cleaned up when the objects are disposed
Solving LOH fragmentation:
- Split list or arrays into smaller objects that remain below 85kB
- allocate the largest and longest-living objects first
- let GC compact the LOH (.net > 4.5.1). If GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce the LOH is compacted during the next full blocking garbage collection, and the property value is reset to default.
- restart program
Generally: do no rely on finalization. 1. It happens unpredictably and may take long time, 2. Finalizer of certain object may not call Dispose() (if it has a bug)
Solution:
- use local rather than global variable
- call Dispose() or use "using(...){ }" concept
- set variable to null when it is not needed anymore
Failing to release unmanaged resources
- practises of deallocating unmanaged code apply
Failing to dispose Drawing objects
e.g Bitmaps, brushes, fonts - these are managed objects, but they hold references to unmanaged objects. These resources are cleaned up when the objects are disposed
Solving LOH fragmentation:
- Split list or arrays into smaller objects that remain below 85kB
- allocate the largest and longest-living objects first
- let GC compact the LOH (.net > 4.5.1). If GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce the LOH is compacted during the next full blocking garbage collection, and the property value is reset to default.
- restart program
Generally: do no rely on finalization. 1. It happens unpredictably and may take long time, 2. Finalizer of certain object may not call Dispose() (if it has a bug)
16_
Available memory resources per 32 and 64 bit systems
On 32 bit system a program can use up to 1.5G memory
64 system can page out memory, which decreases performance, and event run out disk space.
64 system can page out memory, which decreases performance, and event run out disk space.
17_
GC modes
Concurent (desktop apps): GC will not stop the app, the app will just slow.
Server (ASP.net apps): NET will suspend the running application while the garbage collector is running.
Server (ASP.net apps): NET will suspend the running application while the garbage collector is running.
18_
Impact of using GC.Collect()
Using GC.Collect() will cause newly created objects released later (moved to Gen 2) which increases the likelihood of another expensive full collection in the near future.
19_
Example of extension method that adds a method with new name and extends method with the same name
C# sealed class SealedClass { internal void DoSomething() { Console.WriteLine("SealedClass.DoSomething()"); } // cannot be called from extension method protected void DoSomethingProtected() { Console.WriteLine("SealedClass.DoSomethingProtected()"); } internal static void DoSomethingStatic() { Console.WriteLine("SealedClass.DoSomethingStatic()"); } } static class ExtensionClass { internal static void DoSomething(this SealedClass sealedClass) { Console.WriteLine("Gets never called"); } internal static void DoSomething(this SealedClass sealedClass, int i) { sealedClass.DoSomething(); // class method can be called
// sealedClass.DoSomethingProtected(); not available Console.WriteLine("ExtensionClass.DoSomething(int i)"); } internal static void DoSomethingElse(this SealedClass sealedClass) { Console.WriteLine("ExtensionClass.DoSomethingElse()"); } internal static void DoSomethingStatic(this SealedClass sealedClass) { Console.WriteLine("Gets never called"); } } class ExtensionMethodsDemo { internal static void DemoExtensionMethods() { SealedClass sealedClass = new SealedClass(); sealedClass.DoSomething(); // calls SealedClass sealedClass.DoSomething(1); // calls ExtensionClass sealedClass.DoSomethingElse(); // calls ExtensionClass SealedClass.DoSomethingStatic(); // calls SealedClass } }
20_
Write tracing information to log file, console and event log
C# // trace to a text file TextWriterTraceListener textWriterTraceListener = new TextWriterTraceListener(LOG_FILE_NAME); textWriterTraceListener.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.ProcessId | TraceOptions.ThreadId; Trace.Listeners.Add(textWriterTraceListener); // trace to the console Trace.Listeners.Add(new ConsoleTraceListener()); // trace to event log // !! this code must be executed als administrator when the source Basics.exe does not exist ventLogTraceListener eventLogTraceListener = new EventLogTraceListener("Basics.exe"); Trace.WriteLine("Written by Trace.WriteLine()"); Trace.Flush(); Trace.AutoFlush = true; Trace.TraceInformation("Written by Trace.TraceInformation"); // writes datetime + process id + thread id Trace.TraceWarning("Written by Trace.TraceWarning"); Trace.TraceError("Written by Trace.TraceError");
21_
Create TextWriterTraceListener in app.config
XML <configuration> <system.diagnostics> <trace autoflush="true"> <listeners> <remove name="Default"/> <add name="textWriterTraceListenerConfig" type="System.Diagnostics.TextWriterTraceListener" traceOutputOptions="DateTime,Timestamp,Callstack,LogicalOperationStack,ProcessId,ThreadId" initializeData="MyLogFromConfig.log"> </add> </listeners> </trace> </system.diagnostics> </configuration>
22_
Create a trace listener with filter
C# TextWriterTraceListener textWriterTraceListener = new TextWriterTraceListener(LOG_FILE_NAME); EventTypeFilter e = new EventTypeFilter(SourceLevels.Error); // .Error: Verbose, Information, Warning are ignored textWriterTraceListener.Filter = e; Trace.Listeners.Add(textWriterTraceListener); Trace.TraceWarning("DemoEventTraceWithFilter - Trace warning"); // will be ignored (by filter) Trace.TraceError("DemoEventTraceWithFilter - Trace error"); // will be writtenThis can be also done in app.config
XML <add name="textWriterTraceListenerConfig" type="System.Diagnostics.TextWriterTraceListener" initializeData="MyLogFromConfig.log"> <filter type="System.Diagnostics.EventTypeFilter" initializeData="Warning"/> </add>
23_
TraceSwitch to filter messages
C# TraceSwitch traceSwitch = new TraceSwitch("textWriterTraceListener", "description" ); traceSwitch.Level = TraceLevel.Warning; // Off 0, Error 1, Warning 2 default, Info 3, Verbose 4 TextWriterTraceListener textWriterTraceListener = new TextWriterTraceListener(LOG_FILE_NAME); Trace.Listeners.Add(textWriterTraceListener); Trace.WriteLine("switch controlled - no IF"); Trace.WriteLineIf(traceSwitch.TraceVerbose, "switch controlled verbose"); // will be ignored Trace.WriteLineIf(traceSwitch.TraceError, "switch controlled error"); Trace.Flush();or in app.config
XML <system.diagnostics> <switches> <add name="textWriterTraceListener" value="3"/> </switches> ...
24_
Write to Event Log
C# string myAppName = "Basics3.exe"; // event source name must be unique accross all logs // Write to application log
EventLog eventLog = new EventLog("Application", Environment.MachineName, myAppName); EventLog.WriteEntry(myAppName, "Demo error", EventLogEntryType.Error); // !! this code must be executed als administrator when the source does not exist // Write to custom log EventLog customEventLog = new EventLog("ZbynekDemo1", Environment.MachineName, myAppName + "Custom"); customEventLog.WriteEntry("Demo error", EventLogEntryType.Error); // first time you have to close and open Event Viewer to see the new custom event log
25_
How to enable and create and configure console logger in Log4net
Install log4net NuGet package (log4net.dll will be added to project references)
C# using log4net; using log4net.Config; namespace Log4NetBasics { class Program { private static readonly ILog _logger = LogManager.GetLogger("MyLogger"); static void Main(string[] args) { XmlConfigurator.Configure(); // read the configuration from app.config // BasicConfigurator.Configure(); // ! does not read configuration for File or Debug appenders _logger.Info("Info message"); _logger.Warn("Warning message"); _logger.Error("Error message"); Console.ReadLine(); } } }
XML <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <log4net> <appender name="Console" type="log4net.Appender.ColoredConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> </layout> </appender> <root> <level value="ALL"/> <appender-ref ref="Console"/> </root> </log4net> </configuration>
26_
How to format message for log4net and include own property
XML <log4net> <appender name="Console" type="log4net.Appender.ColoredConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger %property{myData} (%file:%line): %message %newline"/> </layout> </appender> ... </log4net>will produce:
2016-05-22 11:00:05,887 [10] ERROR MyLogger Abc (c:\Log4NetBasics\Program.cs:18): Error message%property{myData} will pint out content set as below
C# GlobalContext.Properties["myData"] = "abc";
27_
How to define color for messages for og4net
XML <log4net> <appender name="Console" type="log4net.Appender.ColoredConsoleAppender"> <mapping> <level value="ERROR"/> <foreColor value="Red"/> </mapping> ... </appender> ... </log4net>
28_
Using file and debug appenders in Log4net
Adding another listeners, called appenders, can be done the same way in app.config
XML <log4net> <appender name="File" type="log4net.Appender.RollingFileAppender"> <param name="File" value="c:\\temp\\log4netBasics.log"/> <param name="AppendToFile" value="true"/> <maximumFileSize value="100KB" /> <maxSizeRollBackups value="2" /> <layout type="log4net.Layout.PatternLayout"></layout> </appender> <appender name="DebuggerAppender" type="log4net.Appender.DebugAppender"> <layout type="log4net.Layout.PatternLayout"> </layout> </appender> ... </log4net>
29_
How to output current class and method (for logging)
C# private static void Log(string message) { var frame = new StackFrame(skipFrames: 1); // 1 will get the frame of the caller of the Log method System.Reflection.MethodBase callingMethod = frame.GetMethod(); Console.WriteLine("Class: {0} Method: {1}", callingMethod.DeclaringType.Name, callingMethod); }
30_
Configure value in default app config and read it in code
app.config file contains key-vaulue pair
XML <configuration> <appSettings> <add key="key1" value="value1" /> </appSettings> </configuration>the values can be retrieved as
C#
string settingValue = System.Configuration.ConfigurationManager.AppSettings["key1"];
31_
Get and set values in default config file
Configuration values in default app.config cannot be modified, because the is no setter defined
C#
try
{
System.Configuration.ConfigurationManager.AppSettings.Add("added", "added value");
}
catch (ConfigurationErrorsException ex)
{
Console.WriteLine(ex);
// "The configuration is write protected" exception. When executed from VS or Basics.exe.
}
but you can open the default app.config as a specific file and then you can modify the values.
32_
Get value from specific config
C# ExeConfigurationFileMap map = new System.Configuration.ExeConfigurationFileMap(); map.ExeConfigFilename = "app1.config"; // this can be used for Basics.exe.config or Basics.vshost.exe.config as well Configuration mappedConfiguration = ConfigurationManager.OpenMappedExeConfiguration(map, System.Configuration.ConfigurationUserLevel.None); AppSettingsSection appSettingsSection = (AppSettingsSection)mappedConfiguration.GetSection("appSettings"); // Get string settings = appSettingsSection.Settings["key2"].Value; // Add appSettingsSection.Settings.Add("addedKey", "addedValue"); mappedConfiguration.Save(); // Remove appSettingsSection.Settings.Remove("addedKey"); mappedConfiguration.Save();
33_
How to use properties for configuration
Another way how to store configuration data is to use Properties.Settings class.
- The settings are stored in app.config either in userSettings or applicationSettings sections.
After the creation the Properties\Settings.settings file will be modified.
- The settings are stored in app.config either in userSettings or applicationSettings sections.
XML <configuration> <configSections> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="Basics.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="Basics.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </sectionGroup> </configSections> <userSettings> <Basics.Properties.Settings> <setting name="MySettingForUser" serializeAs="String"> <value>user</value> </setting> </Basics.Properties.Settings> </userSettings> <applicationSettings> <Basics.Properties.Settings> <setting name="MySettingForApp" serializeAs="String"> <value>app</value> </setting> </Basics.Properties.Settings> </applicationSettings> </configuration>- The settings need to be created in the Settings tab in Project properties.
After the creation the Properties\Settings.settings file will be modified.
C# internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { [global::System.Configuration.UserScopedSettingAttribute()] public string MySettingForUser { get { return ((string)(this["MySettingForUser"])); } set { this["MySettingForUser"] = value; } } }The settings can be accessed with the code below:
C# // get application scope setting value string value = Properties.Settings.Default.MySettingForApp; // Properties.Settings.Default.SettingApp = value + "x"; does not compile, SettingApp has no setter // get and set user scope setting value string userValue = Properties.Settings.Default.MySettingForUser; Properties.Settings.Default.MySettingForUser = userValue + "+"; Properties.Settings.Default.Save();
34_
Create simple custom section in config
Define class representing the section
C# class ConfigurationElementSimple : System.Configuration.ConfigurationSection { [System.Configuration.ConfigurationProperty("myValue", IsRequired = true)] public string MyValue { get { return (string)base["myValue"]; } set { base["myValue"] = value; } } [System.Configuration.ConfigurationProperty("myNumber", IsRequired = false)] public int MyNumber { get { return (int)base["myNumber"]; } set { base["myNumber"] = value; } } }Define the section and populate its values in app.config. configSections must be the first section in the app.config. The same section type can be used multiple times.
XML <configuration> <configSections> <section name="simpleCustomSection" type="Basics.ConfigurationElementSimple, Basics"/> <section name="simpleCustomSection2" type="Basics.ConfigurationElementSimple, Basics"/> </configSections> <simpleCustomSection myValue="abc" myNumber="1" /> <configuration>Read content of the section in code.
C# ConfigurationElementSimple config = (ConfigurationElementSimple)System.Configuration.ConfigurationManager.GetSection("simpleCustomSection"); config = (ConfigurationElementSimple)System.Configuration.ConfigurationManager.GetSection("simpleCustomSection2");
35_
Create complex custom section with list in config
Define class representing the section including the collection with its items.
Each item in collection must be identified with unique value.
C# public class ConfigurationCollectionItem : ConfigurationElement { [ConfigurationProperty("name", IsRequired = true, IsKey = true)] public string Name { get { return (string)base["name"]; } } [ConfigurationProperty("detail", IsRequired = false, IsKey = true)] public string Detail { get { return (string)base["detail"]; } } public string UniqueName { get { return string.Format("{0}{1}", Name, Detail); } } } public class MyConfigurationCollection : ConfigurationElementCollection { public ConfigurationCollection() { } protected override ConfigurationElement CreateNewElement() { return new ConfigurationCollectionItem(); } protected override Object GetElementKey(ConfigurationElement element) { return ((ConfigurationCollectionItem)element).UniqueName; } } public class ConfigurationElementComplex : ConfigurationSection { [ConfigurationProperty("id", IsDefaultCollection = false, IsRequired = true)] public string Id { get { return (string)base["id"]; } } [ConfigurationProperty("myList", IsDefaultCollection = false, IsRequired = true)] public MyConfigurationCollection MyList { get { return (MyConfigurationCollection)base["myList"]; } } }Define the section and populate its values in app.config. configSections must be the first section in the app.config.
XML <configuration> <configSections> <section name="complexCustomSection" type="Basics.ConfigurationElementComplex, Basics"/> </configSections> <complexCustomSection id="1"> <myList> <add name="John" detail="abc" /> <add name="Paul" detail="def" /> </myList> </complexCustomSection> <configuration>Read content of the section in code
C# ConfigurationElementComplex config1 = (ConfigurationElementComplex)System.Configuration.ConfigurationManager.GetSection("complexCustomSection"); // string s = ((ConfigurationCollectionItem)config1.MyList[0]).Name; // access not allowed (config1.MyList[0]) foreach(var item in config1.MyList) { string name = ((ConfigurationCollectionItem)item).Name; }
36_
Write a value, Read a value(2 ways) in registry, Test if values exists and delete it
C# // create or overwrite registry value Registry.SetValue(Registry.CurrentUser.Name + @"\Software\Zbynek Cernin\Basics", "TestValue", "abc"); // read registry value string value = (string)Registry.GetValue(Registry.CurrentUser.Name + @"\Software\Zbynek Cernin\Basics", "TestValue", string.Empty); // read registry value - using RegistryKey RegistryKey basicsKey = Registry.CurrentUser.OpenSubKey(@"Software\Zbynek Cernin\Basics"); if (basicsKey != null) { value = (string)basicsKey.GetValue("TestValue"); value = (string)basicsKey.GetValue("TestValue1"); // does not exists - returns null } // test if values exists and delete it
basicsKey = Registry.CurrentUser.OpenSubKey(@"Software\Zbynek Cernin\Basics", writable: true); if (basicsKey != null) { if (basicsKey.GetValueNames().Where(s => s == "TestValue").Count() > 0) { basicsKey.DeleteValue("TestValue"); } }
37_
Create message queue
C# // this code has to run as Admin
System.Messages.MessageQueue.Create(@".\Private$\MyQueue");
38_
Read messages synchronously
C# if (MessageQueue.Exists(@".\Private$\MyQueue")) { MessageQueue mq = new MessageQueue(@".\Private$\MyQueue"); // send mq.Send("Hello " + DateTime.Now.ToString(), "Title"); // receive Message msg = mq.Receive(); };
39_
Read messages asynchronously
C# static void WriteAndReadMessageAsynchronously() { MessageQueue mq = new MessageQueue(@".\Private$\MyQueue"); mq.Send("Hello " + DateTime.Now.ToString(), "Title"); mq.ReceiveCompleted += new ReceiveCompletedEventHandler(MessageReceived); mq.BeginReceive(); } public static void MessageReceived(object source, ReceiveCompletedEventArgs args) { MessageQueue mq = (MessageQueue)source; Message msg = mq.EndReceive(args.AsyncResult); string body = (string)msg.Body; }
40_
Create class instance from its name
C# internal class Person { internal int ID; internal string Name; } // arguments: assembly name, full class name with namespace Person p = new Person() { ID = 1 }; object p1 = Activator.CreateInstance("Basics", "Basics.Person").Unwrap(); p = (Person)p1;
41_
Create a generic class based on dynamic type
Assuming set of classes as data entities
Assuming set of classes as data entities
C# public class BaseClass { public int id; } public class Person : BaseClass { public string FirstName; public string LastName; } public class Department : BaseClass { public string DepartmentName; }and generic converter
C# interface IEntityConverter { BaseClass Deserialize(string data); } public class EntityConverter<T> : IEntityConverter where T : BaseClass { public BaseClass Deserialize(string data) { string debug = typeof(T).ToString(); // see the type to demo that correct type is used return new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<T>(data); // from System.Web.Extensions } }it is possible to create a generic converter class based on dynamicly specified type as a string
C# private static IEntityConverter CreateGenericConverter(string className) { // get full dto object name for given entity name string fullPersonClassName = typeof(Person).FullName; // use Person class to get namespace string nameSpace = fullPersonClassName.Substring(0, fullPersonClassName.LastIndexOf('.')); string fullClassName = nameSpace + "." + className; // get executing assembly name string assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; // construct dto for given entity BaseClass classInstance = (BaseClass)Activator.CreateInstance(assemblyName, fullClassName).Unwrap(); // construct generic converter for given entity dto Type genericConverterType = typeof(EntityConverter<>); Type constructedConverterForType = genericConverterType.MakeGenericType(classInstance.GetType()); object entityConverter = Activator.CreateInstance(constructedConverterForType); return (IEntityConverter)entityConverter; }and it can be used as followed
C# IEntityConverter departmentConverter = CreateGenericConverter("Department"); string sObj = "{\"DepartmentName\":\"IT\",\"id\":1}"; BaseClass obj = departmentConverter.Deserialize(sObj);
42_
Can you compare secure strings
C# System.Security.SecureString NewPassword; System.Security.SecureString NewPassword2; NewPassword.Clear(); NewPassword.AppendChar('a'); NewPassword2.Clear(); NewPassword2.AppendChar('a'); bool b = NewPassword2.Equals(NewPassword); // b is FALSE b = NewPassword.GetHashCode() == NewPassword.GetHashCode(); // b is FALSE
43_
Convert SecureString to string
C# IntPtr sPtr = IntPtr.Zero; try { sPtr = Marshal.SecureStringToBSTR(securePassword); String s1 = Marshal.PtrToStringBSTR(sPtr); StringBuilder sb = new StringBuilder(); for (int i = 0; i < s1.Length; i++) { sb.Append(s1[i]); } return sb.ToString(); } finally { if (ss_bstr1_ptr != IntPtr.Zero) { Marshal.ZeroFreeBSTR(ss_bstr1_ptr); } }
44_
Publish and subscribe string and int events with Caliburn
C# // add reference to Caliburn.micro.dll using Caliburn.Micro; // this is needed in order to see PublishOnUIThread extension method public partial class MainForm : Form { internal static readonly Caliburn.Micro.IEventAggregator _eventAggregator = new Caliburn.Micro.EventAggregator(); public void Publish() { _eventAggregator.PublishOnUIThread("Hello from Caliburn"); _eventAggregator.PublishOnUIThread(123); } } public partial class Form2Calibrun : Form, IHandle<string>, IHandle<int> { public Form2Calibrun() { ... MainForm._eventAggregator.Subscribe(this); } public new void Handle(string message) { label1.Text = (string)message; } public new void Handle(int message) { label1.Text = Convert.ToString(message); } }
45_
How to subscribe (with filter), handle, raise and unsubscribe events with EventAggregator (Prism)
C# // define event object public class MyStringEvent : PubSubEvent<string> { } // string event public class Person { public int Id; public string Name; } public class MyPersonEvent : PubSubEvent<Person> { } / // create aggregator class IEventAggregator _aggregator = new EventAggregator(); // subscribe events _aggregator.GetEvent<MyStringEvent>().Subscribe(StringEventHandler); _aggregator.GetEvent<MyPersonEvent>().Subscribe(PersonEventHandler); // subscribe events with filter SubscriptionToken unsubscribeToken = _aggregator.GetEvent<MyStringEvent>() .Subscribe(StringEventHandler, ThreadOption.UIThread, keepSubscriberReferenceAlive: false, filter: s => s.StartsWith("A")); // handle events private void StringEventHandler(string s) { ... } private void PersonEventHandler(Person p) { ... } // raise event _aggregator.GetEvent<MyStringEvent>().Publish("Hello"); _aggregator.GetEvent<MyPersonEvent>().Publish(new Person() { Name = "John"} ); // unsubscribe _aggregator.GetEvent<MyStringEvent>().Unsubscribe(StringEventHandler); _aggregator.GetEvent<MyStringEvent>().Unsubscribe(unsubscribeToken);
46_
How use Lazy class to create a Singleton
Lazy class can be used to create a thread safe singleton
C# public sealed class MySingleton { private static readonly Lazy<MySingleton> lazy = new Lazy<MySingleton>(() => new MySingleton()); public static MySingleton Instance { get { return lazy.Value; } } private MySingleton() { } }
47_
Convert string to byte[] and back
C# byte[] bytes = Encoding.ASCII.GetBytes(someString);
string someString = Encoding.ASCII.GetString(bytes);
48_
What is x?.propertyOfX
C# string bar = x?.PropertyOfX;is equivalent of
C# string bar = (x == null ? null : x.PropertyOfX);
49_typeof vs GetType()
typeof is an operator to obtain a type known at compile-time
GetType() is a method you call on individual objects
GetType() is a method you call on individual objects
C# string s = "hi"; typeof(string) == s.GetType() // true string obj = "hello"; typeof(object) == s.GetType() // false
50_
Switch based on type
C# Object o = 3; Type t = o.GetType(); var mySwitch = new Dictionary<Type, Action> { { typeof(int), () => { Console.Write("int"); } }, { typeof(string), () => { Console.Write("string"); } }, }; if (mySwitch.ContainsKey(t)) mySwitch[t]();
51_
Check class inheritance with .Is??() methods
C# typeof(Derived).IsSubclassOf(typeof(Base)) // true typeof(Base).IsSubclassOf(typeof(Base)) // false typeof(Base).IsAssignableFrom(typeof(Derived)) // true typeof(Base).IsAssignableFrom(typeof(Base)) // true typeof(int[]).IsAssignableFrom(typeof(uint[])) // true - but not a subclass
52_
Fluent interface
Fluent interface is concept that allows calling methods in chain without storing intermediate result in a variable.
In C# fluent interface is implemented in LINQ using extension methods.
In C# fluent interface is implemented in LINQ using extension methods.
C# // fluent var query1 = arr.Where(x => x > 7).OrderBy(x => x); // progressive var query2a = arr.Where(x => x > 7); var query2b = query2a.OrderBy(x => x);