Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
highlevel:csharp:xtra2 [2009/02/10 12:56] alfred |
highlevel:csharp:xtra2 [2020/05/09 09:25] (actual) |
||
|---|---|---|---|
| Línea 2: | Línea 2: | ||
| + | ===== Sockets ===== | ||
| + | * [[code:tools#sockets|Explicación de sockets]]. | ||
| + | ==== Creación de un servidor RAW ==== | ||
| + | <code csharp> | ||
| + | System.Net.Sockets.TcpListener server = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 2005); | ||
| + | server.Start(); | ||
| + | Byte[] bytes = new Byte[256]; | ||
| + | String data = null; | ||
| + | while (true) | ||
| + | { | ||
| + | System.Net.Sockets.TcpClient client = server.AcceptTcpClient(); | ||
| + | data = null; | ||
| + | System.Net.Sockets.NetworkStream stream = client.GetStream(); | ||
| + | int i; | ||
| + | while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) | ||
| + | { | ||
| + | data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); | ||
| + | Console.WriteLine("Received: {0}", data); | ||
| + | data = data.ToUpper(); | ||
| + | byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); | ||
| + | stream.Write(msg, 0, msg.Length); | ||
| + | Console.WriteLine("Sent: {0}", data); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | Para enviar un "salto de línia" haremos: | ||
| + | <code csharp> | ||
| + | byte[] msg = System.Text.Encoding.ASCII.GetBytes(data + "\n\r"); | ||
| + | stream.Write(msg, 0, msg.Length); | ||
| + | </code> | ||
| + | ===== Expresiones Regulares ===== | ||
| + | ==== In a nutshell ==== | ||
| + | En ''System.Text.RegularExpressions'' existe la clase ''Regex'' que se encarga de localizar combinaciones (matches) de expresiones regulares en un texto. Por ejemplo, su método estático ''Matches'' recibe un texto y una expresión regular y devuelve objetos ''Match'' de las coincidencias. \\ | ||
| + | Un objeto ''Match'' tiene las siguientes propiedades interesantes: | ||
| + | * ''NextMatch()'': | ||
| + | * ''Index'': Posición dentro del string original donde se encuentra el primer carácter de la coincidencial. | ||
| + | * ''Lenght'': | ||
| + | * ''Success'': | ||
| + | * ''Value'': Recoge el substring de la coincidencia encontrada. | ||
| + | <code csharp> | ||
| + | string startBy = "src=\"|src = \"|src= \"|src =\""; | ||
| + | var matches = System.Text.RegularExpressions.Regex.Matches(text, startBy, System.Text.RegularExpressions.RegexOptions.IgnoreCase); | ||
| + | List<string> lImgNames = new List<string>(); | ||
| + | for (int i = 0; i < matches.Count; i++) | ||
| + | { | ||
| + | var match = matches[i]; | ||
| + | int start = match.Index + match.Value.Length; | ||
| + | int end = text.IndexOf("\"", start); | ||
| + | string file = text.Substring(start, end - start); | ||
| + | lImgNames.Add(file); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ===== Comunicación entre procesos ===== | ||
| - | ===== Comunicación entre procesos ===== | ||
| Línea 27: | Línea 80: | ||
| using System.Runtime.Remoting; | using System.Runtime.Remoting; | ||
| </code> | </code> | ||
| + | |||
| === El dominio de la aplicación === | === El dominio de la aplicación === | ||
| Un dominio de aplicación es un proceso dentro del sistema operativo donde una o más aplicaciones residen. Los objetos que se encuentran en el mismo dominio de aplicación se comunican directamente, en cambio, los que están en distintos dominios se comunican a partir del transporte de copias de estos objetos. Existe una clase (**System.MarshalByRefObject**) que sirve como clase base para las clases que intervengan la comunicación e intercambio de mensajes entre dominios de aplicación (si no heredasen serían //marshal by value//). | Un dominio de aplicación es un proceso dentro del sistema operativo donde una o más aplicaciones residen. Los objetos que se encuentran en el mismo dominio de aplicación se comunican directamente, en cambio, los que están en distintos dominios se comunican a partir del transporte de copias de estos objetos. Existe una clase (**System.MarshalByRefObject**) que sirve como clase base para las clases que intervengan la comunicación e intercambio de mensajes entre dominios de aplicación (si no heredasen serían //marshal by value//). | ||
| Línea 48: | Línea 102: | ||
| === El servidor === | === El servidor === | ||
| + | Creamos un canal de servidor a partir de un nombre de canal (en formato string) y lo registramos mediante el método estático de la clase ''ChannelServices'', a este se le pasan dos objetos, un objeto correspondiente al canal en sí y un boolean, que será //true// si el canal será manejado a partir de un protocolo seguro. \\ \\ | ||
| + | Luego deberemos registrar los objetos compartidos a partir del método estático ''RegisterWellKnownServiceType'' dentro de ''RemotingConfiguration'', si lo hacemos mediante ''WellKnownObjectMode.Singleton'' se creará un único objeto objeto, para acceder a él la ruta será ''<nowiki>ipc://nombreDelCanal/NombreDelObjeto</nowiki>''. \\ \\ | ||
| + | Para recoger un objeto utilizaremos el método ''GetObject'' de la clase ''Activator''. | ||
| <code csharp> | <code csharp> | ||
| IpcServerChannel server = new IpcServerChannel("myChannel"); | IpcServerChannel server = new IpcServerChannel("myChannel"); | ||
| Línea 55: | Línea 112: | ||
| c.Value = "Servidor"; | c.Value = "Servidor"; | ||
| </code> | </code> | ||
| + | |||
| === El cliente === | === El cliente === | ||
| + | Únicamente es necesario acceder al objeto a partir de ''Activator.GetObject''. | ||
| <code csharp> | <code csharp> | ||
| - | IpcClientChannel icc = new IpcClientChannel(); | + | // IpcClientChannel icc = new IpcClientChannel(); |
| - | ChannelServices.RegisterChannel(icc, true); | + | // ChannelServices.RegisterChannel(icc, true); |
| - | RemotingConfiguration.RegisterWellKnownClientType(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); | + | // RemotingConfiguration.RegisterWellKnownClientType(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); |
| SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); | SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); | ||
| Console.WriteLine(c.Value); | Console.WriteLine(c.Value); | ||
| Línea 66: | Línea 124: | ||
| ===== Configuración ===== | ===== Configuración ===== | ||
| + | |||
| + | |||
| + | |||
| + | |||
| ==== Fichero app.config ==== | ==== Fichero app.config ==== | ||
| Línea 81: | Línea 143: | ||
| Utilizaremos un objeto de la clase **AppSettingsReader** y su método ''GetValue'': | Utilizaremos un objeto de la clase **AppSettingsReader** y su método ''GetValue'': | ||
| <code csharp> | <code csharp> | ||
| - | new System.Configuration.AppSettingsReader().GetValue("logFile", typeof(String)) | + | (string)new System.Configuration.AppSettingsReader().GetValue("dbFile", typeof(String)); |
| </code> | </code> | ||
| === Agregar secciones === | === Agregar secciones === | ||
| Línea 98: | Línea 160: | ||
| </configuration> | </configuration> | ||
| </code> | </code> | ||
| - | Para leer estas secciones | + | Para leer estas secciones deberemos agregar la referencia al ensamblado ''System.Configuration'' y poder así utilizar la clase ''ConfigurationManager'': |
| + | <code csharp> | ||
| + | IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("log"); | ||
| + | string logFile = (string)confTable["logFile"]; | ||
| + | </code> | ||
| + | === Agregar grupos de secciones === | ||
| + | Podemos agregar grupos de secciones, por ejemplo: | ||
| + | <code xml> | ||
| + | <?xml version="1.0" encoding="utf-8" ?> | ||
| + | <configuration> | ||
| + | <configSections> | ||
| + | <sectionGroup name="atm.ws"> | ||
| + | <section name="dbInfo" type="System.Configuration.DictionarySectionHandler" /> | ||
| + | </sectionGroup> | ||
| + | </configSections> | ||
| + | <atm.ws> | ||
| + | <dbInfo> | ||
| + | <add key="DataSource" value="TheDataSource" /> | ||
| + | <add key="UserName" value="user" /> | ||
| + | <add key="Password" value="pass" /> | ||
| + | </dbInfo> | ||
| + | </atm.ws> | ||
| + | ... | ||
| + | </code> | ||
| + | Y luego acceder a ellas como si accediesemos a una sección personalizada: | ||
| + | <code csharp> | ||
| + | IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("atm.ws/dbInfo"); | ||
| + | string dataSource = (string)confTable["DataSource"]; | ||
| + | </code> | ||
| + | |||
| + | |||
| + | |||
| + | ===== Programación declarativa con C# ===== | ||
| + | * [[code:best-practices#programacion_declarativa|Programación declarativa]] | ||
| + | ==== Métodos ==== | ||
| + | Podemos realizar un bucle ''foreach'' con el método ''List<T>.ForEac'' y una expresión lambda. | ||
| + | <code csharp> | ||
| + | using System; | ||
| + | using System.Collections.Generic; | ||
| + | |||
| + | class Example | ||
| + | { | ||
| + | static void Main() | ||
| + | { | ||
| + | new List<Int32> { 1, 2, 3 } | ||
| + | .ForEach(i => Console.WriteLine(i)); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | De una forma parecida podemos sacar partido del delagado ''Action<T>'', el cual permite una funcion ''Action<Int32>'' el cual encaja con ''Console.WriteLine''. | ||
| + | <code csharp> | ||
| + | using System; | ||
| + | using System.Collections.Generic; | ||
| + | |||
| + | class Example | ||
| + | { | ||
| + | static void Main() | ||
| + | { | ||
| + | new List<Int32> { 1, 2, 3 } | ||
| + | .ForEach(Console.WriteLine); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | También el método ''Enumerable.Range'': | ||
| + | <code csharp> | ||
| + | using System; | ||
| + | using System.Linq; | ||
| + | |||
| + | class Example | ||
| + | { | ||
| + | static void Main() | ||
| + | { | ||
| + | Int32 sum = Enumerable.Range(0, 99) | ||
| + | .Where(i => i % 2 == 0) | ||
| + | .Sum(); | ||
| + | Console.WriteLine(sum); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||