domingo, 24 de septiembre de 2017

Listas, Colas, Pilas y Conjuntos en C# - Parte 1/6: List(T) y ArrayList

Índice

1. Introducción
2. Palabras Clave
3. List<T>
4. ArrayList
5. Conclusiones
6. Literatura & Enlaces

1. Introducción

A partir de este artículo empezamos con una nueva serie llamada Listas, Colas, Pilas y Conjuntos en C#. Esta serie busca hacer una introducción por cada una de estas estructuras de datos o colecciones que implementan las interfaces descritas en anteriormente (Interfaces ICollection y IList en C# - Parte 1/2). Se resaltará la importancia de las implementaciones genéricas; en especial su rendimiento superior respecto a las versiones no-genéricas (disponibles para casos de compatibilidad).


Empezamos con dos clases: List<T> y ArrayList. Clases de uso común para la manipulación de datos que siguen un patrón de organización de sus elementos basado en listas y con acceso con índices.

2. Palabras Clave

  • Algoritmo
  • Arreglo
  • Colección
  • Compatibilidad
  • Estructura de datos
  • Lista

3. List<T>

Clase que implementa las versiones de interfaces IList y IList<T>. Los elementos se acceden a través de un índice, y cuenta con operaciones para ordenar, buscar y manipular sus elementos.

La Figura 1 presenta el grupo de interfaces que implementa esta clase genérica:
Interfaces de List
Figura 1. Interfaces de List ("List(T) Class", 2017).
Al interior de la clase, los elementos se almacenan en un arreglo de objetos; cuando la capacidad de este arreglo es superada se reemplaza por un arreglo de mayor capacidad. Respecto a lo anterior hay que considerar que la operación de inserción resulta lenta debido a que los elementos después del punto de inserción se deben desplazar para almacenar el elemento insertado. Sin embargo, añadir un elemento al final de la lista es rápido (Albahari, 2012).

Buscar elementos es realmente eficiente por medio del algoritmo de búsqueda binaria; al igual que en los arreglos. A comparación con ArrayList, IList<T> es varias veces más efciente debido a que no es necesario efectuar operaciones de boxing y unboxing (Boxing y Unboxing en C#).

Veamos un ejemplo de uso:

List<string> tresMaestros = new List<string>
tresMaestros.Add("Dostoievski");
tresMaestros.AddRange (new [] {"Balzac", "Dickens"});
tresMaestros.Remove("Balzac");
tresMaestros.Insert(0, "Balzac");

tresMaestros.RemoveAt(1); // Remueve el 2do elemento
tresMaestros.RemoveRange(0, 2);

tresMaestros.AddRange (new [] {"Balzac", "Dickens", "Dostoevski"});

tresMaestros.RemoveAll( e =< e.StartsWith("M"));

List<int> longitudNombres = tresMaestros.ConvertAll( e =<T> e.Length);

foreach(string e in tresMaestros){
    Console.WriteLine(e);
}

Existen otros métodos interesantes, como:
  • GetRange
  • Copy
  • ToArray

4. ArrayList

La clase no-genérica ArrayList ("ArrayList Class", 2017), al igual que List<T>, crece o decrece de forma dinámica a medida que se adicionan o remueven elementos. Como advierte Albahari (2012): "ArrayList class is used for backward compatibility with Framework 1.x" Es decir, el programador cuenta con una estructura de datos para soportar requerimientos funcionales o adaptaciones a versiones de la serie 1.x de .NET Framework.

De forma análoga al código anterior, con esta clase podemos escribir:

ArrayList tresMaestros = new ArrayList();
tresMaestros.Add ("Dostoievski");
tresMaestros.AddRange(new [] {"Balzac", "Dickens"});

Para recuperar elementos es necesario hacer un casting o conversión de los elementos:

string dostoievski = (string) tresMestros[0];

Las conversiones a tipos de datos no compatibles con string se efectúan en tiempo de ejecución -i.e., el compilador no las puede verificiar-:

int primerEscritor = (int) tresMaestros[0];

Como punto adicional, la clase System.Linq.Cast permite convetir un objeto ArrayList a un objeto List<T>:

ArrayList numerosPrimos = new ArrayList();
numerosPrimos.AddRange (new[] {2, 91, 101});
List<int> listaNumerosPrimos = numerosPrimos.Cast<int>().ToList();

5. Conclusiones

Exploramos en este artículo dos clases basadas en índices y con la diferencia resaltada de genericidad: List<T> y ArrayList. Se entendió que ArrayList está disponible para suplir requerimientos de compatibilidad hacia atrás, en particular con .NET Framework 1.x. Se presentaron los ejemplos de uso prácticos para conocer la funcionalidad ofrecida a través de métodos de estas dos clases.

En el próximo artículo nos adentraremos en la exposición conceptual de la clase LinkedList<T>.

6. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
List(T) Class (System.Collections.Generic) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
Boxing y Unboxing en C# (2012). Recuperado desde: https://ortizol.blogspot.com.co/2014/03/boxing-y-unboxing-en-c.html
ArrayList Class (System.Collections) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.collections.arraylist(v=VS.100).aspx


O

domingo, 17 de septiembre de 2017

La Clase Array en C# - Parte 3/3

Índice

1. Introducción
2. Palabras Clave
3. Inversión de Elementos
4. Copiar Elementos
5. Conversión
6. Redimensionamiento
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Esta última parte de la serie de artículos Clase Array en C#, describe cuatro operaciones adicionales que el programador puede realizar con un objeto de la clase Array: invertir, copiar, convertir y redimensionar un arreglo. Para ello será necesario explorar métodos como: Reverse, Clone, CopyTo, Copy y ConvertAll.

2. Palabras Clave

  • Arreglo
  • Copiar
  • Conversión
  • Redimensionamiento

3. Inversión de Elementos

Encontramos en la clase Array las versiones sobrecargadas del método Reverse para invertir el orden de los elementos integrales (Albahari, 2012):
  • void Reverse (Array array): esta versión toma un objeto Array e invierte todos los elementos del arreglo.
  • void Reverse (Array array, int index, int length): con esta versión se invierte sólo una porción de los elementos del arreglo pasado como argumento.
Ambas versiones son static.

Un ejemplo de uso podría ser:

Array tresMaestros = Array.CreateInstance(typeOf(string), 3);
tresMaestros.SetValue("Balzac", 0);
tresMaestros.SetValue("Dickens", 1);
tresMaestros.SetValue("Dostoevski", 2);

Al imprimir los elementos del arreglo tresElementos se mostrará: Balzac, Dickens y Dostoevski. Luego al invocar el método static Reverse:

Array.Reverse(tresMaestros);

el contenido del arreglo será: Dostoevski, Dickens y Balzac.

4. Copiar Elementos

Los métodos Clone, CopyTo, Copy y ConstrainedCopy de la clase Array copian los elementos de un arreglo en modo shallow (La Clase Array en C# - Parte 1/3).
  • Clone: Crea una copia de todo el contenido del arreglo.
  • Copy, CopyTo: Crea una copia de un subconjunto de los elementos de un arreglo.
  • ContrainedCopy: Copia los elementos de un arreglo comprobando que no existan errores durante el proceso. Si algo sale mal, la copia se suspende y los cambios se deshacen.

5. Conversión

Para convertir el tipo de dato de los elementos de un arreglo, C# proporciona el método ConvertAll ("Array.ConvertAll", 2017). Este método recibe como argumento el arreglo a convertir, y un delegado que lleva a cabo la conversión en concreto.

Ejemplo de uso:

double[] constantes = {3.14159, 2.71828, 0.57721}
int[] valoresEnteros = Array.ConvertAll (reals, v => Convert.ToInt32(v));

6. Redimensionamiento

El método Array.Resize ("Array.Resize(T)", 2017) crea un nuevo arreglo en el que se copian los elementos de un arreglo fuente; además se espeficia el tamaño del nuevo arreglo por medio de argumento int. La instancia retornada mantiene las mismas referencias de los elementos del arreglo fuente; es decir que se llama a cabo un copiado tipo shallow.

7. Conclusiones

Se describieron los métodos para invertir, copiar, convertir y redimensionar arreglos de la clase Array. Tener conocimiento conceptual de estos elementos de programa nos permitirá escribir aplicaciones que hagan uso de operaciones optimizadas que provee .NET Framework a través de los lenguajes de programación compatibles.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
Array.Reverse Method (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array.reverse(v=vs.110).aspx
La Clase Array en C# - Parte 1/3 (2017). Recuperado desde: https://ortizol.blogspot.com.co/2017/09/la-clase-array-en-csharp-parte-1-3.html
Array.ConstrainedCopy Method (Array, Int32, Array, Int32, Int32) (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array.constrainedcopy(v=vs.110).aspx
Array.ConvertAll(TInput, TOutput) Method (TInput[], Converter(TInput, TOutput)) (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/exc45z53(v=vs.110).aspx
Array.Resize(T) Method (T[], Int32) (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/bb348051(v=vs.110).aspx


O

domingo, 10 de septiembre de 2017

La Clase Array en C# - Parte 2/3

Índice

1. Introducción
2. Palabras Clave
3. Búsqueda
4. Ordenamiento
5. Conclusiones
6. Literatura & Enlaces

1. Introducción

Esta segunda entrada de artículos relacionados con la Clase Array en C# describe los métodos de búsqueda -búsqueda binaria, locativa y por predicado-, y los métodos de ordenamiento de los elementos por su orden natural o siguiendo una regla.

2. Palabras Clave

  • Array
  • Arreglo
  • Búsqueda
  • Ordenamiento

3. Búsqueda

La clase Array ofrece tres clases de métodos de búsqueda para arreglos unidimensionales (Albahari, 2012):
  • Método static sobrecargado BinarySearch ("Array.BinarySearch", 2017): busca sobre un arreglo ordenado usando el algoritmo de búsqueda binaria.
  • Búsqueda locativa: los métodos IndexOf y LastIndex recuperan el primer y último elemento de un arreglo.
  • Búsqueda por predicados: los métodos Find, FindLast, FindIndex, FindLastIndex, FindAll, Exists y TrueForAll realizan una búsqueda partiendo de un predicado lógico de tipo Predicate<T>.
Cuando no se encuentra un elemento en un arreglo usando cualquiera de los métodos de búsqueda, éstos retornan -1 o el valor por defecto del tipo paramétrico -0 para valores numéricos o null para string, por ejemplo-.

Para los métodos basados en el algoritmo de búsqueda binaria, el cual es de alto desempeño, el requisito indispensable es que los elementos estén ordenados.

Para la búsqueda locativa, se efectúa una enumeración de los elementos y se obtiene el índice del primer u último elemento que coincide con un valor particular.

A través de un delegado (Delegados en C# - Parte 1: Introducción) o una expresión lambda (Expresiones Lambda en C# - Parte 1: Introducción a las Expresiones Lambda) es posible establecer un predicado para la búsqueda de uno o más valores en un arreglo. La forma sintáctica que tiene un predicado es ("Predicate(T) Delegate", 2017):

public delegate bool Predicate<T>(T object)

Un ejemplo de uso básico podría ser:

static void Main()
{
    string[] tresMaestros = { "Balzac", "Dickens", "Dostoievski"};
    string encontrado = Array.Find(tresMaestros, ContieneO);
   
    Console.WriteLine(encontrado); // Dostoievski
}

static bool ContieneO(string escritor)
{
    return escritor.Contains("o");
}

Otra forma simplificada:

static void Main()
{
    string[] tresMaestros = { "Balzac", "Dickens", "Dostoievski"};
    string encontrado = Array.Find(tresMaestros, delegate(string escritor){return escritor.Contains("o");});
   
    Console.WriteLine(encontrado); // Dostoievski
}

Aunque con una expresión lambda se obtiene una versión más simple:

static void Main()
{
    string[] tresMaestros = { "Balzac", "Dickens", "Dostoievski"};
    string encontrado = Array.Find(tresMaestros, n => n.Contains("o"));
   
    Console.WriteLine(encontrado); // Dostoievski
}

[Nota: El lector puede leer la documentación para comprender los demás métodos que aceptan un predicado para efecutar una búsqueda.]

4. Ordenamiento

Existen 17 versiones sobrecargadas del método Sort en la Array. Una forma básica de uso sobre un único arreglo podría ser:

int[] numeros = {5, 2, 3, 7};
Array.Sort(numeros);    // {2, 3, 6, 7}

O usar la versión que acepta dos arreglos:

int[] numeros = {5, 2, 3, 7};
string[] tresMaestros = { "Dostoievski", "Dickens", "Balzac"};
Array.Sort(numeros, tresMaestros);    // {2, 3, 6, 7}, { "Balzac", "Dickens", "Dostoievski"}

Vale agregar que existen otras versiones sobrecargadas que facilitan especificar un delegado de comparación para la personlización la forma en que se debe llegar la comparación:

public delegate int Comparison<T>(T x, T y)

5. Conclusiones

Hemos explorado las formas esenciales para buscar y ordernar los elementos en una colección de tipo Array. Estos métodos comprenden operaciones fundamentales para manipular elementos de datos para solución de problemas.

El siguiente artículo se estudiará cómo revertir, copiar, convertir y redimensionar un arreglo de tipo Array.

6. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
Array Class (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
Array.BinarySearch Method (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array.binarysearch(v=vs.110).aspx
Delegados en C# - Parte 1: Introducción (2017). Recuperado desde: https://ortizol.blogspot.com/2014/05/Delegados-en-csharp-parte-1-introduccion.html
Expresiones Lambda en C# - Parte 1: Introducción a las Expresiones Lambda (2017). Recuperado desde: https://ortizol.blogspot.com/2014/06/expresiones-lambda-en-csharp-parte-1-introduccion-a-las-expresiones-lambda.html
Predicate(T) Delegate (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/bfcke1bz.aspx?f=255&MSPPError=-2147217396


O

lunes, 4 de septiembre de 2017

La Clase Array en C# - Parte 1/3

Índice

1. Introducción
2. Palabras Clave
3. Generalidades
3.1 Jerarquía de herencia e implementación
3.2 Sintetización de pseudo-subtipos
3.3 Tipos por referencia y por valor
3.4 Comparación y copiado
4. Creación e Indexación
5. Enumeración
5.1 Ciclo for
5.2 Ciclo mejorado foreach
5.3 Método de extensión ForEach
6. Longitud y Rango
6.1 Longitud
6.2 Rango
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Esta serie de tres artículos comprende el estudio de la clase Array en lenguaje de programación C#. Esta clase, como ya veremos, es una implementación particular de IList; tanto su versión no-genéria como genérica, dado que el acceso a los elementos se realiza a través de un índice. Aún sí, sabremos que no todos los métodos de estas clases tendrán un codificación específica, sino que se lanzará la excepción NotSupportedException.


La primera parte es una introducción acerca de los fundamentales. La segunda se enfocará en búsqueda y ordenamiento de elementos. La última tratará acerca de copiado, conversión y redimensionamiento de arreglos.

2. Palabras Clave

  • Array
  • Arreglo
  • Coleccion
  • Copia deep
  • Copia shallow
  • Estructura de datos
  • Índice
  • List

3. Generalidades

3.1 Jerarquía de herencia e implementación

La clase Array es una de las clases base que implementa las interfaces estándar de colección; i.e., IList, ICollection y IEnumerable (Albahari, 2012). Se trata de un tipo abstracto que provee métodos estáticos y de instancia para realizar operaciones sobre arreglos: creación, manipulación, búsqueda y ordenamiento ("Array Class", 2017).


Se sabe que uno de los principios de .NET Framework es la unificación de tipos de datos, y en este caso la clase Array provee un conjunto de métodos comunes para todos los diferentes tipos de datos adyacentes a los elementos de un arreglo.


Con relación a lo anterior, los arreglos son considerados una estructura de datos o colección esencial en el lenguaje de programación C# y todos los demás lenguajes de programación compatibles con la CLR. En el artículo Arreglos en C# se expone la sintaxis declarativa y de manipulación de arreglos sobre C#.

3.2 Sintetización de pseudo-subtipos

Otra característica interna y esencial es la sintetización de pseudo-subtipos de arreglos tanto para el tamaño o dimensión como para el tipo de dato subyacente. Por ejemplo, si se crea un arreglo con el tipo de dato string, las interfaces génericas que implementa Array cambiarán su tipo paramétrico a este mismo: IList<string>.


Adicionalmente la máquina virtual CLR asignará al arreglo recién creado un espacio contiguo en la memoria de trabajo. Aunque esto resulte eficiente en el acceso basado en índices, no se permite el redimensionamiento en el ciclo de ejecución del programa. El método Resize<T> ("Array.Resize(T)", 2017) permite cambiar el tamaño de un arreglo especificado por uno nuevo; sin embargo, cualquier otra referencia al arreglo anterior continuará sin ser modificada. Para solucionar esta carencia, se opta por el uso de colecciones dinámicas como List<T>.

3.3 Tipos por referencia y por valor

El almacenamiento de los tipos por valor se computa a partir del tamaño del tipo dato; es decir, que si un arreglo de 5 elementos de tipo de dato int -4 bytes-, ocupará 20 bytes. Este no es el caso para los arreglos que localizan tipos por referencia: cada elemento del arreglo sólo ocupará el espacio dependiendo de la arquitectura del sistema: 4 bytes en un ambiente de 32 bits u 8 bytes en un ambiente de 64 bits.


Vale tomar el ejemplo expuesto por Albahari (2012) para la ilustración gráfica de este modelo de almacenamiento:
Modelo almacenamiento tipos por referencia y por valor
Figura 1. Modelo almacenamiento tipos por referencia y por valor (Albahari, 2012).

Esta ilustración puede traducirse al siguiente código fuente:

StringBuilder[] builders = new StringBuilder[5];
builders[0] = new StringBuilder("builder1");
builders[1] = new StringBuilder("builder2");
builders[2] = new StringBuilder("builder3");

long[] numbers = new long[3];
numbers[0] = 12345;
numbers[1] = 54321;

3.4 Comparación y copiado

Todos los arreglos en su defecto son tipos por referencia a razón que Array es una clase. Si se tienen dos variables, digamos arreglo1 y arreglo2, entonces al realizar la siguiente asignación arreglo1 = arreglo2, ambas apuntarán al mismo arreglo en memoria.


En cuanto a la comparación del contenido de los arreglos -i.e., comparación estructural- el operador == y el método Equals producen false como resultado: 


object[] a1 = {"Balzac", 1799, true};
object[] a2 = {"Balzac", 1799, true};

Console.WriteLine(a1 == a2);
Console.WriteLine(a1.Equals(a2));


Para realizar comparación estructural podemos usar un comparador de igualdad personalizado o por medio de la clase static StructuralComparisons (disponible a partir de la versión 4.0 de .NET Framework): 


IStructuralEquatable se1 = a1;
Console.WriteLine(se1.Equals(a2, StructuralComparisons.StructuralEqualityComparer);

Esta sentencia da como resultado true, a razón de que el contenido de ambos arreglos es igual.


Por su parte, la operación de clonación, la cual se lleva a cabo con el método Clone, como en 


arregloB = arregloA.Clone()


genera una copia shallow: lo que quiere decir que sólo se copia la memoria que representa al arreglo y no los valores de los elementos y sus datos localizados en la memoria. La Figura 2 ilustra mejor este concepto a partir del siguiente código fuente (Albahari, 2012):


StringBuilder[] builders2 = builders;
StringBuilder[] shalowClone = (StringBuilder[]) builders.Clone();

Copia shalow
Figura 2. Copia shalow.

Para crear una copia del contenido y las referencias de un arreglo, se debe efectuar una copia de tipo deep. Para lograrlo es necesario iterar el arreglo y realizar una clonación por cada elemento. Esto también aplica para los demás tipos de colecciones de .NET Framework.

4. Creación e Indexación

C# provee diferentes alternativas para la creación y acceso por medio de índices. Una formá básica comprende el uso de esta sintaxis:

int[] arregloEnteros = {2, 3, 5};
Console.WriteLine(arregloEnteros[0]); // Primer elemento
Console.WriteLine(arregloEnteros[arregloEnteros.Length - 1]); // Último elemento


Otra de las formas disponibles consiste en usar el método static CreateInstance:
Versiones sobrecargadas de CreateInstance
Tabla 1. Versiones sobrecargadas de CreateInstance ("Array.CreateInstance", 2017).

Entonces el arreglo definido anteriormente también se puede escribir así:

Array arregloEnteros = Array.CreateInstance(typeof(int), 3);
arregloEnteros.SetValue(2, 0);
arregloEnteros.SetValue(3, 1);
arregloEnteros.SetValue(5, 2);
Console.WriteLine(arregloEnteros.GetValue(0)); // Primer elemento
Console.WriteLine(arregloEnteros.GetValue(arregloEnteros.Length - 1)); // Último elemento


Nótese que el tipo de dato asociado al arreglo se define a través del operador typeof (El Método GetType y el Operador typeof en C#).



Como se advierte en Albahari (2012), independiente del mecanismo de inicialización de un arreglo que se use, cada uno de sus elementos se inicializan de manera automática.

5. Enumeración

Para recorrer un arreglo es posible utilizar diferentes mecanismos. Partimos de esta definición:

int[] arregloEnteros = {2, 3, 5};

5.1 Ciclo for

for(int i = 0; i < arregloEnteros.Length; ++i)
{
    Console.WriteLine(arregloEnteros[i]);
}

Aquí el recorrido se realiza a partir de un índice: la variable entera i. El arreglo itera desde el primer elemento -0- hasta que la condición de continuación de ciclo no se cumpla -i == arregloEnteros.Length-

5.2 El ciclo mejorado foreach

foreach(int valor in arregloEnteros)
{
    Console.WriteLine(valor)
}

Este mecanismo es más simple que el anterior, pero no permite la modificación de los datos adyacentes al arreglo.

5.3 El método de extensión ForEach

Con el método de extensión ForEach, se especifica el arreglo a ser recorrido y la acción a aplicar en cada elemento:

Array.ForEach(arregloEnteros, Console.WriteLine);

6. Longitud y Rango

6.1 Longitud

Para obtener la longitud o tamaño de una dimensión de un arreglo se usan los métodos de instancia Array.GetLength y Array.GetLongLength.

En lo que se refiere a las propiedades Length y LongLength, éstas obtienen la cantidad total de elementos en todas las dimensiones del arreglo.

Otros métodos interesantes son:
  • GetLowerBound: Obtiene el índice del primer elemento de la una dimensión especificada.
  • GetUpperBound: Obtiene el índice del último elemento de la una dimensión especificada.

6.2 Rango

El rango de un arreglo se obtiene a través de la propiedad Rank.

7. Conclusiones

En esta primera parte comprendimos los principios de la clase Array: una clase unificadora para definir arreglos básicos, ya sea de tipos por valor o tipos por referencia. Estudiamos las formas de declarar y acceder los elementos: básada en índices y métodos static y de instancia. Más adelante nos concentramos entender cómo se recorre o enumera los elementos: for, foreach y ForEach. Al final, se reconocieron los métodos para obtener el tamaño y el número de dimensiones de un arreglo.

8. Literatura & Enlaces

Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.
Array Class (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
Array Class (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array(v=vs.110).aspx
Arreglos en C# (2017). Recuperado
desde: https://ortizol.blogspot.com/2013/09/arreglos-en-c.html
Array.CreateInstance Method (System) (2017). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.array.createinstance(v=vs.110).aspx


O