[Notas de estudio de C#] Tipo de valor (1)

Insertar descripción de la imagen aquí

Aunque las personas con conocimientos básicos de programación pueden empezar rápidamente con C#, todavía necesitan aprender las características y los conceptos básicos de C#. Esta serie son mis notas para aprender C# y están escritas enteramente de acuerdo con los documentos oficiales de Microsoft , pero no son adecuadas para personas sin conocimientos de programación.


Arquitectura .NET

Los programas C# se ejecutan en .NET, que es un sistema de ejecución virtual y un conjunto de bibliotecas de clases llamado Common Language Runtime (CLR). CLR es
la implementación de Microsoft del estándar internacional Common Language Infrastructure (CLI). La CLI es la base para crear entornos de ejecución y desarrollo donde los lenguajes y las bibliotecas pueden trabajar juntos sin problemas.

En pocas palabras, C# se ejecuta en .NET. .NET es un marco de desarrollo. Los códigos en varios lenguajes pueden interactuar entre sí dentro del marco . Las definiciones de tipos de datos en C# siguen a CTS para convertirse en datos comunes de CLR. tipos. .NET proporciona una máquina virtual llamada CLR. CLR es un entorno de ejecución virtual basado en la especificación CLI . CLI es una especificación de desarrollo entre lenguajes que define el lenguaje intermedio IL , el código IL y los recursos para la compilación multiplataforma (como mapas de bits y cadenas) se almacenan en un ensamblado con una extensión generalmente .dll . Cuando se ejecuta C#, el IL se convierte en un conjunto de instrucciones nativo realizando una compilación justo a tiempo (JIT) en el CLR para lograr una implementación multiplataforma .


Hola Mundo

using System;

class Hello
{
    
    
    static void Main()
    {
    
    
        Console.WriteLine("Hello, World");
    }
}

Lo anterior es Hola, mundo de C#. Parece una combinación de C++ y Java.

Cuando usamos espacios de nombres, usamos usingpalabras clave + nombres de espacios de nombres. Luego definimos una clase y definimos Main()métodos en ella. Los métodos se declaran Mainusando modificadores. staticLos métodos de instancia pueden usar la palabra clave thispara hacer referencia a una instancia de objeto envolvente específica, mientras que los métodos estáticos pueden funcionar sin hacer referencia a un objeto específico. Por convención, Mainlos métodos estáticos son los puntos de entrada de los programas C#.

Bien, ahora has aprendido C#


Tipos y variables (importantes)

Hay dos tipos principales en C#, uno es el tipo de valor y el otro es el tipo de referencia . Es muy importante entender estos dos tipos.

Las variables de tipos de valor contienen sus datos directamente. Las variables de tipo de referencia almacenan una referencia a datos (llamada "Objeto"). Para los tipos de referencia, dos variables pueden hacer referencia al mismo objeto; las operaciones realizadas en una variable pueden afectar el objeto al que hace referencia la otra variable. Con los tipos de valor, cada variable tiene su propia copia de los datos; por lo tanto, las operaciones realizadas en una variable no afectan a la otra (excepto las variables de parámetro ref y out).

¿Qué son los tipos de valor y los tipos de referencia?

Enlace original: Cómo evitar operaciones de boxeo y unboxing en C#

  • ¿Qué son los tipos de valores?

Todas las estructuras son clases derivadas directamente del tipo abstracto System.ValueType, que a su vez se deriva directamente de System.Object. Según la definición, todos los tipos de valores deben derivarse de System.ValueType y todas las enumeraciones se derivan de la clase abstracta System.Enum, que a su vez se deriva de System.ValueType.

Todos los tipos de valor están sellados implícitamente para evitar que se derive cualquier otro tipo del tipo de valor.

  • ¿Qué son los tipos de referencia?

Todas las clases en C# son tipos de referencia, incluidas las interfaces.

Entonces, los tipos de datos en el lenguaje C# en realidad se derivan de la clase base abstracta de .NET.

tipo de valor

tipo simple

  • Enteros con signo: sbyte, short, int, long
  • Tipo de entero sin signo: byte, ushort, uint, ulong
  • Carácter Unicode: char, que representa la unidad de código UTF-16
  • Punto flotante binario IEEE: flotante, doble
  • Número de coma flotante decimal de alta precisión: decimal
  • Valor booleano: bool, que indica un valor booleano (verdadero o falso)

tipo de enumeración

  • Tipo definido por el usuario en formato enum E {...}. El tipo de enumeración es un tipo único que contiene constantes con nombre. Cada tipo de enumeración tiene un tipo base (debe ser uno de los ocho tipos de enteros). El conjunto de valores de un tipo de enumeración es el mismo que el conjunto de valores del tipo subyacente.

tipo de estructura

  • Un tipo definido por el usuario del formulario struct S {…}
  • Tipos de valor que pueden ser nulos
    Extensiones a todos los demás tipos de valores cuyo valor es nulo
  • Tipo de valor de tupla
    Tipo definido por el usuario en el formato (T1, T2,…)

tipo simple

Los tipos simples incluyen números enteros, punto flotante, caracteres y booleanos. Es decir, tipos comunes en algunos lenguajes de programación.

Enteros con signo: sbyte, short, int, long
Estos son muy básicos, puedes leer la documentación oficial, los tipos especiales son sbyte, byte, nint y nuint. Este último se agregó en C# 11 y se utiliza para obtener el tamaño del rango positivo nativo en diferentes sistemas operativos:
para nint: Int32.MinValue a Int32.MaxValue.
Para nuint: UInt32.MinValue a UInt32.MaxValue.

El tamaño del rango de sbyte y byte es 1 byte. sbyte incluye el rango negativo, pero sbyte no cumple con CLR, por lo que solo nos centramos en el byte. La diferencia entre byte y otros tipos de enteros es que asignarle directamente un carácter ASCII no implica una conversión implícita o explícita entre el tipo de carácter y el tipo de byte, por lo que no es factible, por ejemplo byte b='a'.

Para datos enteros, generalmente cambia cuando los datos se desbordan más allá del rango (por supuesto, esto está relacionado con el cambio de bits en el byte). Por ejemplo, tipo de byte 255+1=0, tipo de byte 127+1= -128 (especialmente, el registro representa 000000000 y 10000000representa -128)

Insertar descripción de la imagen aquíSólo hay una conversión implícita entre tipos numéricos de punto flotante: flotante a doble. Sin embargo, cualquier tipo de punto flotante se puede convertir a cualquier otro tipo de punto flotante mediante una conversión explícita.

En C#, también podemos usar definiciones de tipo .NET o entre lenguajes, como int a=1y System.Int32 a=1son consistentes.
Al asignar valores a números enteros, puede utilizar decimal, hexadecimal y binario. El decimal es un número normal. El hexadecimal comienza con 0Xy el binario 0Bcomienza con. También podemos usar decimales como separador al asignar valores _, por ejemplo, int a=3000y int a =3_000son equivalentes.

Finalmente, la mayoría de los tipos numéricos pueden tener caracteres de sufijo, como 0.1ff para flotante y 21LL para largo.


tipo de enumeración

Un tipo de enumeración es un tipo de valor definido por un conjunto de constantes con nombre de un tipo numérico integral subyacente. Para definir un tipo de enumeración, utilice la palabra clave enum y especifique los nombres de los miembros de la enumeración:

enum Season
{
    
    
    Spring,
    Summer,
    Autumn,
    Winter
}

El valor de una variable de un tipo de enumeración sólo puede ser uno de varios valores internos. Por ejemplo Season S1 =Season.Spring;. La impresión directa imprimirá los nombres de los miembros de la enumeración. Pero, de hecho, los valores en el tipo de enumeración corresponden al número entero predeterminado. Si no hay definición, comienza desde 0 y aumenta de arriba a abajo. Si está definido, es el valor entero definido. También se puede lograr una conversión explícita de valores enteros utilizando nombres de tipos de enumeración.

print(S1) // Spring
print((int)S1) // 0
var b = (Season)1;
Console.WriteLine(b);  // output: Summer

Una representación alternativa de una enumeración acepta una representación binaria y se puede operar bit a bit mediante operadores lógicos, lo cual es un uso común.
Cuando usamos [Flags]instrucciones para indicar una enumeración como un campo de bits, cada opción en la enumeración se llamará campo de bits. En este momento, las opciones se pueden fusionar o combinar mediante operadores lógicos:

[Flags]
public enum Days
{
    
    
    None      = 0b_0000_0000,  // 0
    Monday    = 0b_0000_0001,  // 1
    Tuesday   = 0b_0000_0010,  // 2
    Wednesday = 0b_0000_0100,  // 4
    Thursday  = 0b_0000_1000,  // 8
    Friday    = 0b_0001_0000,  // 16
    Saturday  = 0b_0010_0000,  // 32
    Sunday    = 0b_0100_0000,  // 64
    Weekend   = Saturday | Sunday
}
public class FlagsEnumExample
{
    
    
    public static void Main()
    {
    
    
        Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
        Console.WriteLine(meetingDays);
        // Output:
        // Monday, Wednesday, Friday

        Days workingFromHomeDays = Days.Thursday | Days.Friday;
        Console.WriteLine($"Join a meeting by phone on {
      
      meetingDays & workingFromHomeDays}");
        // Output:
        // Join a meeting by phone on Friday

        bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
        Console.WriteLine($"Is there a meeting on Tuesday: {
      
      isMeetingOnTuesday}");
        // Output:
        // Is there a meeting on Tuesday: False

        var a = (Days)37;
        Console.WriteLine(a);
        // Output:
        // Monday, Wednesday, Saturday
    }
}

método de extensión

En los tipos de enumeración, normalmente no podemos definir métodos, pero podemos "agregar métodos" a los tipos existentes definiendo métodos de extensión sin modificar el tipo. Los métodos de extensión se utilizan para ampliar los tipos de valores. Por ejemplo, si desea agregar un método de procesamiento para eliminar espacios para todas las cadenas, no es necesario definir una clase y luego definir métodos y variables de cadena en ella. Puede utilizar métodos de extensión directamente, pero las condiciones que deben cumplir los métodos de extensión son:

  • Se requieren métodos estáticos en clases estáticas.
  • El tipo del primer parámetro es el tipo que se va a extender y se debe agregar la palabra clave this para identificarlo como un método de extensión.

En general, implemente métodos de extensión sólo como último recurso y con precaución. Los métodos de extensión no se pueden llamar a través del nombre de la clase, sino directamente usando el tipo.

namespace ExtensionMethods
{
    
    
    public static class MyExtensions
    {
    
    
        public static int WordCount(this string str)
        {
    
    
            return str.Split(new char[] {
    
     ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}
// 上述扩展方法定义在了一个命名空间中的类中的一个方法,定义在命名空间中在调用时会更安全
// 在静态类中定义静态方法,并以添加this关键字标识类型传入
using ExtensionMethods;
string s = "Hello Extension Methods";
int i = s.WordCount();

El siguiente ejemplo muestra oficialmente un método de extensión que vincula una interfaz. Cualquier clase que herede esta interfaz puede llamar a este método de extensión cuando no hay un método interno definido con el mismo nombre que el método de extensión.

// Define an interface named IMyInterface.
namespace DefineIMyInterface
{
    
    
    using System;

    public interface IMyInterface
    {
    
    
        // Any class that implements IMyInterface must define a method
        // that matches the following signature.
        void MethodB();
    }
}

// Define extension methods for IMyInterface.
namespace Extensions
{
    
    
    using System;
    using DefineIMyInterface;

    // The following extension methods can be accessed by instances of any
    // class that implements IMyInterface.
    public static class Extension
    {
    
    
        public static void MethodA(this IMyInterface myInterface, int i)
        {
    
    
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, int i)");
        }

        public static void MethodA(this IMyInterface myInterface, string s)
        {
    
    
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, string s)");
        }

        // This method is never called in ExtensionMethodsDemo1, because each
        // of the three classes A, B, and C implements a method named MethodB
        // that has a matching signature.
        public static void MethodB(this IMyInterface myInterface)
        {
    
    
            Console.WriteLine
                ("Extension.MethodB(this IMyInterface myInterface)");
        }
    }
}

// Define three classes that implement IMyInterface, and then use them to test
// the extension methods.
namespace ExtensionMethodsDemo1
{
    
    
    using System;
    using Extensions;
    using DefineIMyInterface;

    class A : IMyInterface
    {
    
    
        public void MethodB() {
    
     Console.WriteLine("A.MethodB()"); }
    }

    class B : IMyInterface
    {
    
    
        public void MethodB() {
    
     Console.WriteLine("B.MethodB()"); }
        public void MethodA(int i) {
    
     Console.WriteLine("B.MethodA(int i)"); }
    }

    class C : IMyInterface
    {
    
    
        public void MethodB() {
    
     Console.WriteLine("C.MethodB()"); }
        public void MethodA(object obj)
        {
    
    
            Console.WriteLine("C.MethodA(object obj)");
        }
    }

    class ExtMethodDemo
    {
    
    
        static void Main(string[] args)
        {
    
    
            // Declare an instance of class A, class B, and class C.
            A a = new A();
            B b = new B();
            C c = new C();

            // For a, b, and c, call the following methods:
            //      -- MethodA with an int argument
            //      -- MethodA with a string argument
            //      -- MethodB with no argument.

            // A contains no MethodA, so each call to MethodA resolves to
            // the extension method that has a matching signature.
            a.MethodA(1);           // Extension.MethodA(IMyInterface, int)
            a.MethodA("hello");     // Extension.MethodA(IMyInterface, string)

            // A has a method that matches the signature of the following call
            // to MethodB.
            a.MethodB();            // A.MethodB()

            // B has methods that match the signatures of the following
            // method calls.
            b.MethodA(1);           // B.MethodA(int)
            b.MethodB();            // B.MethodB()

            // B has no matching method for the following call, but
            // class Extension does.
            b.MethodA("hello");     // Extension.MethodA(IMyInterface, string)

            // C contains an instance method that matches each of the following
            // method calls.
            c.MethodA(1);           // C.MethodA(object)
            c.MethodA("hello");     // C.MethodA(object)
            c.MethodB();            // C.MethodB()
        }
    }
}
/* Output:
    Extension.MethodA(this IMyInterface myInterface, int i)
    Extension.MethodA(this IMyInterface myInterface, string s)
    A.MethodB()
    B.MethodA(int i)
    B.MethodB()
    Extension.MethodA(this IMyInterface myInterface, string s)
    C.MethodA(object obj)
    C.MethodA(object obj)
    C.MethodB()
 */

Supongo que te gusta

Origin blog.csdn.net/milu_ELK/article/details/132057477
Recomendado
Clasificación