Foro Oficial de C#

C# – Bitmap – Como Convertir Una Imagen a Escala de Grises

Hola a todos , Este articulo es una copia cruzada de mi blog original, visítalo en:

http://juank.black-byte.com/c-bitmap-convertir-imagen-escala-grises/

-------------------
Hola, hace apenas unos días publiqué un artículo para convertir una imagen a escala de grises utilizando XNA Framework:
C# – XNA- Como Convertir Una Imagen a Escala de Grises

Bien como no todo mundo conoce XNA Framework he decidido hacer una versión más accesible utilizando el objeto Bitmap de System.Drawing. Algunas cosas serán un ligeramente más difíciles pero en esencia es lo mismo.

Nuevamente explicare el tema de la conversión de Color para evitar el ir y venir al link anterior.

Cómo Convertir una Imagen a Escala de Grises

Básicamente para que una imagen sea vea en tonos de gris se requiere que los tres componentes básicos del color ( en el computador: rojo, verde, azul – RGB por sus siglas en ingles ) tengan más o menos la misma intensidad, podemos decir que si queremos convertir un pixel a su equivalente en escala de grises bastaría con hacer algo como esto:


  1. Sumar los valores de los componentes de color del pixel, es decir sumar R + G + B
  2. Sacar el promedio de esa suma
  3. El valor hallado se debe asignar a R, G y B
Con estos tres pasos ya logramos que el pixel sea de color gris ya que cada uno de sus componentes tiene el mismo valor.

Hay muchas otras formas de hacerlo, incluso alguien que haya trabajado previamente con imágenes puede tener su propia versión de como implementarlo de acuerdo a lo que necesite o al tiempo que tenga. Pero existe una manera ampliamente conocida y aceptada en el gremio de las personas que trabajan con imágenes y visión por computador esa manera es la que aprenderemos a efectuar.


El ojo humano y su sensibilidad

Bien, resulta que el ojo humano es mucho más sensible a los colores verdes y rojos que al azul, por lo que en cuanto a precepción de iluminación se trata nuestro ojo reconoce los patrones de iluminación en color en las siguientes proporciones para cada componente:


  • Rojo:30%
  • Verde:59%
  • Azul:11%

Así que lo más adecuado es calcular el valor de cada componente de color con base a esta proporción y de este modo se obtiene el pixel de color gris con la iluminación adecuada para que nuestro ojo lo perciba como un mejor equivalente a su versión en color.

Manos A La Obra, Tiempo de Programar


Los Bitmap tienen diversos formatos, el más normal hoy día es el de color de 24 bit, el cual tambien es el valor por defecto cuando cargamos imagenes jpg, en este artículo trabajaremos diseñando un algoritmo para 24 bit de color, a diferencia de como se hizo en el artículo de XNA donde presumimos que trabajabamos con imagenes de 32 bit. Para visualizar un objeto Bitmap basta con usar un PictureBox y a este se le asigna la imagen en su atributo Image, tal como lo vemos a continuación:
PHP:
 private void Form1_Load(object sender, EventArgs e)
        {
            Bitmap imagen = new Bitmap("conejo.jpg");
            pictureBox1.Image = imagen;
        }

Ahora lo que haremos es crear una función que reciba como parámetro un objeto Bitmap ( o imagen ) y devuelva un nuevo Bitmap ( o imagen ) convertido a escala de grises:
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);
 
            return target;
        }
Padding y Stride

El siguiente paso es obtener del bitmap la información de los pixeles que lo conforman, esta tarea si bien es sencilla es un poco más complicada de hacer a lo que es con un Texture2D de XNA, debido a que el objeto Bitmap representa su información de color fielmente a lo que es un archivo bmp.

Por ello se debe tener en cuenta que no todos los bytes son información de color, algunos de estos bytes solo son de relleno y ello puede cambiar de un Bitmap a otro segun sus dimensiones y profundidad de color, esta caracteristica es normalmente conocida como padding y en su momento se implemento para hacer que la lectura del archivo bmp fuera mucho mas rápida al poder cargarla en bloques de enteros.
Asi que lo siguiente a realizar es obtener la información de la imagen lo cual lo hacemos con el método LockBits, el cual retorna un objeto BitmapData
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);             
            BitmapData bmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
                                                 ImageLockMode.ReadOnly, 
                                                 source.PixelFormat);
            
            return target;
        }
Sin embargo BitmapData no nos sirve para recorrer byte por byte la información de color, por lo que ahora debemos convertir bmpData a un byte[]… pero Como?

Debemos apoyarnos en los mecanismos de Marshal provistos por el .net Framework, la clase Marshal permite por ejemplo convertir un bloque de memoria no administrado en un bloque administrado, el objeto bmpData tiene un atributo Scan0 que no es más que un puntero al arreglo de bytes donde esta la información del color, así que podemos utilizar ese puntero para crear poner la información en nuestro array de bytes.

Pero antes debemos crear el array de bytes, el tamaño del array debe ser básicamente ancho x alto x número de bytes por pixel… pero… hay que tener en cuenta el padding…los bytes de relleno. Calcular el padding es muy fácil aunque es dependiente sobre todo de la profundidad del color, pero el objeto bmpData tiene un atributo llamado Stride el cual es el ancho en bytes de cada línea de pixeles incluyendo el stride, así que nuestra formula para hallar el tamaño del array de bytes se reduce a: bmpData.Stride * alto
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);   
          
            BitmapData bmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
                                                 ImageLockMode.ReadOnly, 
                                                 source.PixelFormat);
 
            byte[] targetBytes = new byte[bmpData.Stride * source.Height ];
 
            
            return target;
        }
El engorroso sistema de acceso a los pixeles

Ahora utilizando Marshal obtenemos el array de bytes:
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);   
          
            BitmapData bmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
                                                 ImageLockMode.ReadOnly, 
                                                 source.PixelFormat);
 
            byte[] targetBytes = new byte[bmpData.Stride * source.Height ];
 
            Marshal.Copy(bmpData.Scan0, targetBytes, 0, targetBytes.Length);
            
            return target;
        }
como tambien necesitamos acceder a la infromación en bytes del bmp de destino es necesario repetir las mismas tres operaciones pero en LockBits ahora colocamos WriteOnly.
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);   
          
            BitmapData bmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
                                                 ImageLockMode.ReadOnly, 
                                                 source.PixelFormat);
 
            byte[] targetBytes = new byte[bmpData.Stride * source.Height ];
 
            Marshal.Copy(bmpData.Scan0, targetBytes, 0, targetBytes.Length);
            
            BitmapData targetData = target.LockBits(new Rectangle(0, 0, target.Width, target.Height),
                                     ImageLockMode.WriteOnly,
                                     target.PixelFormat);
            byte[] targetBytes = new byte[targetData.Stride * targetData.Height];
            Marshal.Copy(targetData.Scan0, targetBytes, 0, targetBytes.Length);
 
            return target;
        }
Como es casi el mismo código podemos optimizarlo y organizarlo un poco así:
PHP:
 private byte[] GetImageBytes(Bitmap image, ImageLockMode lockMode, out BitmapData bmpData)
        {
            bmpData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                                     lockMode, image.PixelFormat);
 
            byte[] imageBytes = new byte[bmpData.Stride * image.Height];
            Marshal.Copy(bmpData.Scan0, imageBytes, 0, imageBytes.Length);
 
            return imageBytes;
        }
 
        private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);
            BitmapData targetData, sourceData;
 
            byte[] sourceBytes = GetImageBytes(source, ImageLockMode.ReadOnly, out sourceData);
            byte[] targetBytes = GetImageBytes(target, ImageLockMode.ReadWrite,out targetData); 
                       
            return target;
        }
Ahora se debe recorrer el array de bytes para convertirlo a escala de grises, para poder hacerlo necesitamos recorrer el arreglo en saltos de a pixel, si trabajamos con BMP de 24 bit el tamaño de cada pixel es de 3 bytes. En un Bitmap el formato de color viene en BGR (Blue Green Red) mientras que en XNA viene en BGRA (Blue Green Red Alpha) teniendo en cuenta esto la implementación para convertir los bytes a escala grises queda:
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);
            BitmapData targetData, sourceData;
 
            byte[] sourceBytes = GetImageBytes(source, ImageLockMode.ReadOnly, out sourceData);
            byte[] targetBytes = GetImageBytes(target, ImageLockMode.ReadWrite,out targetData); 
                       
            //recorrer los pixeles
            for (int i = 0; i < sourceBytes.Length; i += 3)
            {
                //ignorar el padding, es decir solo procesar los bytes necesarios
                if ( (i + 3) % (source.Width * 3) > 0 )
                {
                    //Hallar tono gris
                    byte y = (byte)(sourceBytes[i+2] * 0.3f
                                 + sourceBytes[i + 1] * 0.59f
                                 + sourceBytes[i] * 0.11f);
 
                    //Asignar tono gris a cada byte del pixel
                    targetBytes[i + 2] = targetBytes[i + 1] = targetBytes[i] = y;
                }
            }
 
            return target;
        }
Finalmente hay que copiar el array de bytes modificado al bitmap de destino, y desbloquear ambos bitmaps:
PHP:
 private Bitmap CreateGrayScaleBitmap(Bitmap source)
        {
            Bitmap target = new Bitmap(source.Width, source.Height, source.PixelFormat);
            BitmapData targetData, sourceData;
 
            byte[] sourceBytes = GetImageBytes(source, ImageLockMode.ReadOnly, out sourceData);
            byte[] targetBytes = GetImageBytes(target, ImageLockMode.ReadWrite,out targetData); 
                       
            //recorrer los pixeles
            for (int i = 0; i < sourceBytes.Length; i += 3)
            {
                //ignorar el padding, es decir solo procesar los bytes necesarios
                if ( (i + 3) % (source.Width * 3) > 0 )
                {
                    //Hallar tono gris
                    byte y = (byte)(sourceBytes[i+2] * 0.3f
                                 + sourceBytes[i + 1] * 0.59f
                                 + sourceBytes[i] * 0.11f);
 
                    //Asignar tono gris a cada byte del pixel
                    targetBytes[i + 2] = targetBytes[i + 1] = targetBytes[i] = y;
                }
            }
 
            Marshal.Copy(targetBytes, 0, targetData.Scan0, targetBytes.Length);
 
            source.UnlockBits(sourceData);
            target.UnlockBits(targetData);
 
            return target;
        }
Wowfff! finalmente asignamos la imagen al PictureBox:
PHP:
 private void Form1_Load(object sender, EventArgs e)
        {
            Bitmap imagen = new Bitmap("conejo.jpg");
            pictureBox1.Image = imagen;
            pictureBox2.Image = CreateGrayScaleBitmap(imagen);
        }
image1.png
 
Me retracto si se pude manejar una grilla en WPF, no de la misma forma de DataGridView pero ofrece la misma funcionalidad y en mi concepto me parece mas flexible que el DataGridView de WinForm.

Manana coloco la forma como lo hice y como lo vinculo a una fuente de datos de SqlServer en cualquiera de sus versiones.

Manana coloco el ejemplo de esto en el foro

Suerte a Todos:p
 
Oiga JuanK, he estado mirando que WPF no trae un control DataGridView, hay que hacer referencia al de Winform y queda visualmente horrible, y este control es muy importante en el desarrollo que estoy haciendo. Valla he estado leyendo y me encuentro que si quiero algo bonito me toca pagar por ello.

Si no me equivoco y esto resulta verdad, con el amor que le tengo a .NET y Microsoft, se le fue la liebre con este tema. sequire investigando y les cuento .


No he hecho este cursito de WPF, pero esta en lista... y supongo que es como los otros que he hecho, excelente :D

http://www.desarrollaconmsdn.com/msdn/CursosOnline/Curso_WPF/index.html


SuerteX :)
 
Bueno les adjunto el codigo que me permite usar un Grid en WPF sin necesidad de usar el datagridview del .NET 2.0.


<Window x:Class="GrillaWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Grilla en WPF" Height="301" Width="375" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="Cabecera">
<StackPanel Orientation="Vertical" Margin="-5,-5,-5,-5" Width="100">
<StackPanel.Background>

<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF223B84" Offset="1"/>
<GradientStop Color="#FF57A0F4" Offset="0.5"/>
<GradientStop Color="#FF4B94EC" Offset="0.5"/>
</LinearGradientBrush>
</StackPanel.Background>

<TextBlock Margin="10,10,10,10" Text="{Binding}" VerticalAlignment="Center" Foreground="White"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ListView Name="DataList" ItemTemplate="{DynamicResource CustomerTemplate}" ItemsSource="{Binding Path=Table}" Margin="0,0,0,34">
<ListView.Background>
<LinearGradientBrush EndPoint="0.939,0.919" StartPoint="0.061,0.081">
<GradientStop Color="LightSkyBlue" Offset="0"/>
<GradientStop Color="LightSkyBlue" Offset="1"/>
</LinearGradientBrush>
</ListView.Background>

<ListView.View>
<GridView ColumnHeaderTemplate="{StaticResource Cabecera}">
<GridViewColumn Header="Prefijo" DisplayMemberBinding="{Binding Path=Prefijo}" ></GridViewColumn>
<GridViewColumn Header="Numero" DisplayMemberBinding="{Binding Path=Numero}"/>
<GridViewColumn Header="SerialImpresora" DisplayMemberBinding="{Binding Path=SerialImpresora}"/>
<GridViewColumn Header="Recibo" DisplayMemberBinding="{Binding Path=Recibo}"/>
<GridViewColumn Header="RucCliente" DisplayMemberBinding="{Binding Path=RucCliente}"/>
<GridViewColumn Header="EsAnulado" DisplayMemberBinding="{Binding Path=EsAnulado}"/>
<GridViewColumn Header="IdTipoDocumento" DisplayMemberBinding="{Binding Path=IdTipoDocumento}"/>

</GridView>
</ListView.View>
</ListView>
</Grid>


</Window>


Los campos que se llaman DisplayMember en XAML son los campos que traeras de tu base de datos, hay que tener en cuenta que XAML es CaseSensitive por eso deben escribir los campos tan cual como vendran en la consulta SQL, aun es un poco temprano para decir que esta hecha en su totalidad ya que me falta manejar ciertos eventos en el grid, por otro lado muy bueno lo que se puede generar con WPF ya que te permite asignar una gran cantidad de texturas a los controles sin mencionar la experiencia que tiene el usuario.

Cabe resaltar que WPF separa la capa de diseno (XAML) con la capa de de funcionalidad (Los archivos de Codigo C# o VB.NET) .

Adjunto el proyecto.

mas adelante estare hablando de este tema por aqui.




 

Archivos adjuntos

  • Imagen1.GIF
    Imagen1.GIF
    47.5 KB · Visitas: 109
  • Imagen2.jpg
    Imagen2.jpg
    94.8 KB · Visitas: 100
  • GrillaWPF.rar
    71.2 KB · Visitas: 90
  • Me gusta
Reacciones: 2 personas
Hola!

Alguien conoce algun tuto donde sugieran alguna forma de restringir el uso de el software que uno este haciendo en mas de un equipo. Necesito algo para ponerle "seguridad" de coquito a la ejecucion del programa sea por medio de serial, cpuid no se... alguna idea??

Mil gracias!
 
  • Me gusta
Reacciones: 2 personas
Sabe que si cambia hard toca recompilar..



SuerteX :)

no claro no.
la idea es que ese tipo de tecnicas se valen del proceso de instalación de la App...

una forma segura de complementarla seria en el proceso de instalación correr el programa, generar los id y, luego proceder a encriptarlos en un archivo de configuracion.

de tal forma que cuando la aplicacion inicia esta obtiene de una vez los id, luego extrae los id encriptados en el xml , los desencripta y luego los compara...

no es dificil de hacer y no requiere recompilar. XD


Yo siempre digo que mis ayudas son más de mecanismo y no de política, y esta claro que el ejemplo que di en msdn es de mecanismo, la politica de donde albergar las claves si encriptarlas o no etc, corre por cuenta de cada cual. :alien:
 
no claro no.
la idea es que ese tipo de tecnicas se valen del proceso de instalación de la App...

una forma segura de complementarla seria en el proceso de instalación correr el programa, generar los id y, luego proceder a encriptarlos en un archivo de configuracion.

de tal forma que cuando la aplicacion inicia esta obtiene de una vez los id, luego extrae los id encriptados en el xml , los desencripta y luego los compara...

no es dificil de hacer y no requiere recompilar. XD


Yo siempre digo que mis ayudas son más de mecanismo y no de política, y esta claro que el ejemplo que di en msdn es de mecanismo, la politica de donde albergar las claves si encriptarlas o no etc, corre por cuenta de cada cual. :alien:
Pero con eso que estas diciendo, si el usuario lleva la app a otro pc y la instala se generaran unos ID validos con lo cual el la podra seguir instalando en cuantos pc desee porque el programa arranca a validar ID una vez instalada y ejecutada la aplicacion, no antes.

No me cuadra en la cabeza como poder hacer una restriccion logicamente bien hecha con el CPU ID...
 
Pero con eso que estas diciendo, si el usuario lleva la app a otro pc y la instala se generaran unos ID validos con lo cual el la podra seguir instalando en cuantos pc desee porque el programa arranca a validar ID una vez instalada y ejecutada la aplicacion, no antes.
CLARO!!
por eso es que el proceso de instalación lo debes hacer tu o uno de tus funcionarios, no el usuario:

instalan la aplicacion normalmente y luego corren un utilitario NO ENTREGABLE que es el que genera los ID de esa maquina y los deja en el archivo de configuración pero encriptado!!

ahora sino vez la posibilidad de tu mismo hacer la instalación entonces puedes exponer esa misma funcionalidad a traves de un web service, es decir que tu aplicación requiera activación por internet , y la funcionalidad seria básicamente la misma con un mecanismo de validación que envia los id al webservice, este verifica los registros del cliente y compara los cpuid, si el cliente tiene licencias disponibles guarda el cpuid y valida el uso de la App, sino tiene licencias disponibles, es decir ya tenia la licencia asignada a otra CPU ID pues no los dejara usar el sware, esto implicaria que el Sw al menos una vez cada X tiempo valide contra internet si esta o no autorizado, como funcionan por ejemplo muchos de los sware de adobe.

Tambien puedes dar los instaladores y que la activacion sea por telefono, el usuario abre el programa, este le pide activacion y le salen unos codigos ( los id) , el usuario te llama te da los codigos y tu le devuelves los codigos encriptados indicandole que los peque en la pantlla que el programa le indica, el le da aceptar al programa y el programa guarda los codigos encriptados en el archivo de configuracion, en adelanta la aplicacion le funcionara pues ya tiene los codigos equivalentes al cpuid de esa maquina.
 
A eso que dice Venom me referia ;)

Edit: Otra cosa que puede hacer es un generador de clave tomando en cuenta el nombre de la entidad a la que le instala el soft ligado con el CPU Id y otros datos que quiera unir y con ellos crear un clave de instalacion o activacion ;).


SuerteX :)
 
Por mi parte quedo bastante claro... xD al menos la base de lo que se debe tener en cuenta, en unos dias inciare a implementar esa parte asi que luego les cuento como me va yendo =)

Gracias a los dos!
 
Hola... vine pero ya con otra.

Estuve buscando un metodo para encriptar passwords y llegue a un codigo sugerido aca: http://www.daniweb.com/forums/showthread.php?t=49360&highlight=encrypt+c%23

El cual trabaja con MD5:
Código:
using System.Security.Cryptography;
using System.Text;
public static String EncryptPass(String inp)
{
            MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
            byte[] tBytes = Encoding.ASCII.GetBytes(inp);
            byte[] hBytes = hasher.ComputeHash(tBytes);

            StringBuilder sb = new StringBuilder();
            for (int c = 0; c < hBytes.Length; c++)
                sb.AppendFormat("{0:x2}", hBytes[c]);

            return (sb.ToString());
}
Este metodo queda perfecto si uno encriptara la constraseña en c#, la guardara encriptada en la BD y luego cada que fuera a comparar la contraseña que estan ingresando se encriptaria y se compara con la encriptada de la BD; por lo que no habria que desencriptar el password para aprobarlo. El punto es que la aplicacion tiene una opcion de recordar el password en caso de que se olvide, y si este esta guardado en la base de datos encriptado, no hay forma de que yo lo recuerde sin desencriptarlo.

He estado leyendo y dicen que MD5 es "one way encrypter" osea que solo sirve para encriptar y no permite desencriptar.

Que metodo hay para poder hacer lo que necesito en este caso? Encriptar un password y poder desencriptarlo eventualmente.
 
Hola... vine pero ya con otra.

Estuve buscando un metodo para encriptar passwords y llegue a un codigo sugerido aca: http://www.daniweb.com/forums/showthread.php?t=49360&highlight=encrypt+c#

El cual trabaja con MD5:
Código:
using System.Security.Cryptography;
using System.Text;
public static String EncryptPass(String inp)
{
            MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
            byte[] tBytes = Encoding.ASCII.GetBytes(inp);
            byte[] hBytes = hasher.ComputeHash(tBytes);

            StringBuilder sb = new StringBuilder();
            for (int c = 0; c < hBytes.Length; c++)
                sb.AppendFormat("{0:x2}", hBytes[c]);

            return (sb.ToString());
}
Este metodo queda perfecto si uno encriptara la constraseña en c#, la guardara encriptada en la BD y luego cada que fuera a comparar la contraseña que estan ingresando se encriptaria y se compara con la encriptada de la BD; por lo que no habria que desencriptar el password para aprobarlo. El punto es que la aplicacion tiene una opcion de recordar el password en caso de que se olvide, y si este esta guardado en la base de datos encriptado, no hay forma de que yo lo recuerde sin desencriptarlo.

He estado leyendo y dicen que MD5 es "one way encrypter" osea que solo sirve para encriptar y no permite desencriptar.

Que metodo hay para poder hacer lo que necesito en este caso? Encriptar un password y poder desencriptarlo eventualmente.


MD5 no es para encriptar , es para producir un hash... es decir la informacion si se pierde, te recomiendo utilizar RSA, puedes generar un ceritificado para tu aplicación con las herramientas del .net framework y con ese certificado puedes cifrar y descifrar con RSACryptoServiceProvider.

Tambien con la misma clase puedes generar una llave que reemplace el certifiado y usar dicha llave.


saludos.
 
Señores, yo por aqui para hacer una pregunta corta.

Estoy mirando el codigo en donde se llama al metodo del metodo, es decir:

myclass.mymethod1().mymethod2();

¿como se hace eso?¿pa que eso? o bueno, no tanto para que, porque como todos sabemos ti tengo un metodo que devuelve un int, yo podria hacer:

myclass.myIntMethod().ToString() y me convierte el numerito en un string para yo entregarlo.

Espero ser claro, ya busqué en google por metodos de metodos, pero no encuentro mucha informacion, me ayudarian mucho si me explicaran, gracias.
 
mymethod1 debe estar retornando un delegado el cual es un "array de funciones" o un puntero a varias funciones, y de ahi se debe estar llamando la otra.

Es a lo unico que le veo logica en mi excaso conocimiento...
 
Señores, yo por aqui para hacer una pregunta corta.

Estoy mirando el codigo en donde se llama al metodo del metodo, es decir:

myclass.mymethod1().mymethod2();

¿como se hace eso?¿pa que eso? o bueno, no tanto para que, porque como todos sabemos ti tengo un metodo que devuelve un int, yo podria hacer:

myclass.myIntMethod().ToString() y me convierte el numerito en un string para yo entregarlo.

Espero ser claro, ya busqué en google por metodos de metodos, pero no encuentro mucha informacion, me ayudarian mucho si me explicaran, gracias.

no son métodos de métodos de métodos... eso no existe.

realmente lo que pasa es que:


PHP:
myclass.myIntMethod().ToString();
se ejecuta en orden de izquierda a derecha por lo cual

PHP:
myclass.myIntMethod()
Devuelve Int y cualquier objeto tipo Int tiene ToString()...
asi que ese codigo es lo mismo que hacer esto:


PHP:
Int a = myclass.myIntMethod();
a.ToString();
Por lo cual
myclass.mymethod1().mymethod2();
es equivalente a :
PHP:
ObjetoRetornado a= myclass.mymethod1();
a.mymethod2();
 
Mmmm... ok JuanK_solocodigo, lo que pasa es que tengo curiosidad porque donde estoy trabajando trabajan con un metodo, para hacerlo simple en el foro, se llama "myMethod1()" y cuando yo digito en el VisualStudio eso, luego que le doy el "." no solo me salen los metodos base que son "ToString()", "GetType()", sino que tambien me salen otros metodos que los programadores agregaron, ¿como hacen eso? :D

Gracias por el tiempo.