你需要知道的关于C#语言类、类型的信息

作者:微信公众号:【架构师老卢】
7-12 20:24
24

概述:想象一下,你正在建造一座乐高城堡。你不会在墙壁上使用与窗户相同的部件,对吧?在 C# 中,类就像你的乐高积木,不同类型的类适用于应用程序中的不同工作。这篇文章将讨论 C# 中的各种类类型,并帮助你为你的项目选择正确的类类型!核心类类型按数据存储引用类型这些类型存储对实际数据位置的引用(内存地址)。将引用类型变量分配给另一个变量会创建内存地址的副本,而不是数据本身。这对于经常修改的复杂对象很有用。类:最常见的用户定义蓝图public class User {     public string Name { get; set; }     public int Age { get; set

想象一下,你正在建造一座乐高城堡。你不会在墙壁上使用与窗户相同的部件,对吧?在 C# 中,类就像你的乐高积木,不同类型的类适用于应用程序中的不同工作。这篇文章将讨论 C# 中的各种类类型,并帮助你为你的项目选择正确的类类型!

核心类类型

按数据存储

引用类型

这些类型存储对实际数据位置的引用(内存地址)。将引用类型变量分配给另一个变量会创建内存地址的副本,而不是数据本身。这对于经常修改的复杂对象很有用。

:最常见的用户定义蓝图

public class User  
{  
    public string Name { get; set; }  
    public int Age { get; set; }  
  
    public void Welcome()  
    {  
        Console.WriteLine($"Hello, my name is {Name}!");  
    }  
}  
  
public class Program {  
    public static void Main()  
    {  
        User user1 = new User { Name = "Niraj", Age = 30 };  
        User user2 = user1; // Assigning a reference type variable creates a copy of the reference  
  
        user1.Welcome(); // Output: Hello, my name is Niraj!  
        user2.Name = "Alice"; // Modifying user2 also affects user1 due to shared reference  
  
        user1.Welcome(); // Now outputs: Hello, my name is Alice!  
    }  
}

接口:类要遵循的契约,促进代码的可重用性

public interface IProduct  
{  
    string GetName();  
    double GetPrice();  
}  
  
public class Product : IProduct // Concrete class implementing the interface  
{  
    public string Name { get; set; }  
    public double Price { get; set; }  
  
    public string GetName()  
    {  
        return Name;  
    }  
  
    public double GetPrice()  
    {  
        return Price;  
    }  
}  
public static class Program  
{  
    public static void Main()  
    {  
        IProduct product = new Product { Name = "Book", Price = 24.95 };  
        Console.WriteLine($"Product name: {product.GetName()}"); // Output: Product name: Book  
        Console.WriteLine($"Product price: {product.GetPrice():C2}"); // Output: Product price: $24.95  
    }  
}

抽象类:继承的基类,将在后面部分解释。

Delegate :对具有特定签名的方法的引用

public class DelegateSample   
{  
    public delegate int StringToIntDelegate(string value); // Delegate signature  
  
    public static int ParseInt1(string value)  
    {  
        return int.Parse(value);  
    }  
  
    public static int ParseInt2(string value)  
    {  
        return int.Parse(value) + 10;  
    }  
}  
using static DelegateSample;  
  
public static class Program  
{  
  
    public static void Main()  
    {  
        StringToIntDelegate converter1 = ParseInt1; // Assigning a method to the delegate  
        StringToIntDelegate converter2 = ParseInt2; // Assigning a method to the delegate  
  
        int number1 = converter1("10"); // Calling the delegate (which calls ParseInt1)  
        int number2 = converter2("10"); // Calling the delegate (which calls ParseInt2)  
        Console.WriteLine($"Converted number: {number1}"); // Output: Converted number: 10  
        Console.WriteLine($"Converted number: {number2}"); // Output: Converted and added 10 : 20  
    }  
}

我们定义了一个委托类型,该类型指定了一个接受字符串并返回一个整数的方法。该方法是执行字符串到整数转换的具体方法。该方法是执行字符串到整数转换并加 10 的另一种具体方法。

然后,我们将该方法分配给委托变量。现在,包含对 的引用。和 也是如此。

值类型

相反,值类型将数据的实际值直接存储在变量本身中。分配值类型变量将创建全新的数据副本。这对于性能至关重要的简单数据结构非常有用。

结构体:类似于类,但直接在变量中存储数据

using System;  
  
public struct Point  
{  
    public int X { get; set; }  
    public int Y { get; set; }  
  
    public Point(int x, int y)  
    {  
        X = x;  
        Y = y;  
    }  
  
    public void Translate(int dx, int dy)  
    {  
        X += dx;  
        Y += dy;  
    }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        Point point1 = new Point { X = 5, Y = 10 };  
        Point point2 = point1; // Assigning a value type variable creates a completely new copy  
  
        point1.Translate(2, 3); // Modifying point1 doesn't affect point2  
  
        Console.WriteLine($"point1: ({point1.X}, {point1.Y})"); // Output: (7, 13)  
        Console.WriteLine($"point2: ({point2.X}, {point2.Y})"); // Output: (5, 10) (Unaffected)  
    }  
}

枚举:一组命名的整数常量

public enum DayOfWeek  
{  
    Sunday,  
    Monday,  
    Tuesday,  
    Wednesday,  
    Thursday,  
    Friday,  
    Saturday  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        DayOfWeek today = DayOfWeek.Thursday; // Assigning an enum value  
        Console.WriteLine($"Today is {today}"); // Output: Today is Thursday  
  
        // Accessing enum values by index  
        int todayIndex = (int)today; // Enum can be implicitly cast to its underlying type (int)  
        Console.WriteLine($"Today's index is: {todayIndex}"); // Output: Today's index is: 3  
  
        // Using switch statement with enums  
        switch (today)  
        {  
            case DayOfWeek.Saturday:  
            case DayOfWeek.Sunday:  
                Console.WriteLine("It's the weekend!");  
                break;  
            default:  
                Console.WriteLine("Back to work!");  
                break;  
        }  
    }  
}  

在这里,我们定义了一个以命名常量命名的枚举,用于一周中的每一天。

根据定义

标准班

.NET Framework 提供了大量预定义的类,如 、 和 。这些提供了您可以轻松使用的常用功能。

public static class Program  
{  
    public static void Main()  
    {  
        string message = "This is a string!";  
        int length = message.Length; // Get string length  
        Console.WriteLine(length);  // Output: 17  
    }  
}

自定义类

这些类封装了特定于问题域的数据(属性)和功能(方法)(例如,、、)。

public class Order  
{  
    public int OrderId { get; set; }  
    public List<Product> Items { get; set; } // Using another standard class (List)  
  
    public double CalculateTotal()  
    {  
        double total = 0;  
        foreach (Product item in Items)  
        {  
            total += item.Price;  
        }  
        return total;  
    }  
}  
  
public class Product  
{  
    public string Name { get; set; }  
    public double Price { get; set; }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        Order order = new Order();  
        order.OrderId = 100;  
  
        order.Items = new List<Product>();  
        order.Items.Add(new Product { Name = "Shirt", Price = 19.99 });  
        order.Items.Add(new Product { Name = "Hat", Price = 14.50 });  
  
        double total = order.CalculateTotal();  
        Console.WriteLine($"Order total: {total:C2}"); // Output: $34.49  
    }  
}

此自定义类管理订单详细信息,并使用自定义方法计算总价。该类表示订单中的产品。

继承和关系

抽象类(继承的基类)

抽象类充当其他类要继承的蓝图。它可以定义常见的属性、方法,甚至是抽象方法(无需实现)。然后,子类(也称为具体类)必须实现这些抽象方法来提供特定的功能。这对于定义基本行为和对派生类强制执行某些规则非常有用。

public abstract class Shape  
{  
    public abstract void Draw(); // Enforces subclasses to implement drawing behavior  
}  
public static class Program  
{  
    public static void Main()  
    {  
        // You cannot directly create an instance of an abstract class  
         Shape shape = new Shape(); // Compiler error!  
    }  
}

抽象类定义了形状的蓝图,规定了子类(如下图所示)必须实现的方法。

混凝土类(全功能类)

具体类是一个功能齐全的类,可以实例化并直接使用。它实现了所有必需的功能,并且不包含任何抽象方法。您创建的大多数自定义类都将是具体类。

public abstract class Shape  
{  
    public abstract void Draw(); // Enforces subclasses to implement drawing behavior  
  
}  
  
public class Circle : Shape  
{  
    public double Radius { get; set; }  
    public override void Draw() // Implements abstract Draw method  
    {  
        Console.WriteLine("Drawing a circle with radius: {0}", Radius);  
    }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        Circle circle = new Circle { Radius = 5.0 };  
        circle.Draw(); // Output: Drawing a circle with radius: 5  
    }  
}

该类继承自该方法,并为该方法提供具体的实现,特别是对于圆。

密封类(防止继承)

密封类可防止其他类从它继承。这对于表示最终完整实现的类非常有用,不应进一步扩展。

public sealed class MathUtil // Sealed class to prevent inheritance  
{  
    public static int Add(int a, int b)  
    {  
        return a + b;  
    }  
}  
  
public class ScienceUtil :  MathUtil// This class cannot inherit from MathUtil due to being sealed  
{  
    // Error: 'NotAMathUtil' cannot inherit from sealed type 'MathUtil'  
}

在这里,我们定义了一个名为 的密封类。这样可以防止任何其他类从它继承。然后,我们尝试创建一个继承自 的类。但是,代码将导致编译器错误,因为代码是密封的。

专业班级类型

按用途

静态类(实用函数和常量)

无法实例化,仅包含静态成员(静态方法和属性)。静态类通常用于不需要创建对象的实用工具函数或常量。(例如,MathStringExtensions)

public static class MathUtil  
{  
    public static int Add(int a, int b)  
    {  
        return a + b;  
    }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        int sum = MathUtil.Add(5, 3);  
        Console.WriteLine($"Sum: {sum}"); // Output: Sum: 8  
    }  
}

静态类提供了像加法 () 这样的实用函数,可以直接使用,而无需创建此类的对象。

嵌套类(在另一个类中定义)

在另一个类中定义,创建层次结构关系。这对于帮助程序类或与外部类紧密耦合的类非常有用。

public class OrderProcessor  
{  
    public class OrderDetails  
    {  
        public int ItemCount { get; set; }  
    }  
  
    public int ProcessOrder(Order order)  
    {  
        OrderDetails details = new OrderDetails(); // Create nested class instance  
        if (order.Items != null) // Check if Items is null  
        {  
            details.ItemCount = order.Items.Count;  
  
            return details.ItemCount;  
        }  
        else  
        {  
            return 0; // Set ItemCount to 0 if Items is null  
        }  
    }  
}  
  
public class Order  
{  
    public int OrderId { get; set; }  
    public List<Product> Items { get; set; } = new List\<Product>();  
  
    public double CalculateTotal()  
    {  
        double total = 0;  
        foreach (Product item in Items)  
        {  
            total += item.Price;  
        }  
        return total;  
    }  
}  
  
public class Product  
{  
    public string Name { get; set; }  
    public double Price { get; set; }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        // Creating sample products  
        Product product1 = new Product { Name = "Product 1", Price = 10.50 };  
        Product product2 = new Product { Name = "Product 2", Price = 20.75 };  
  
        // Creating sample order with products  
        Order order1 = new Order();  
        order1.Items.Add(product1);  
        order1.Items.Add(product2);  
  
        // Processing the order  
        OrderProcessor processor = new OrderProcessor();  
        int count1 = processor.ProcessOrder(order1);  
  
        // Displaying order details  
        Console.WriteLine("Order 1 Details:");  
        Console.WriteLine($"Total Products: {count1}");  
        Console.WriteLine($"Total Price: ${order1.CalculateTotal()}");  
  
        // Creating another sample order  
        Order order2 = new Order();  
        order2.Items.Add(product1); // Adding the same product as before  
  
        // Processing the second order  
        int count2 = processor.ProcessOrder(order2);  
  
        // Displaying second order details  
        Console.WriteLine("\\nOrder 2 Details:");  
        Console.WriteLine($"Total Products: {count2}");  
        Console.WriteLine($"Total Price: ${order2.CalculateTotal()}");  
    }  
}

嵌套在 中的类有助于管理与外部类的功能紧密耦合的特定订单详细信息。

按功能(C# 9 及更高版本)

Record 类(不可变的数据传输对象)

一种特殊类型的类,针对不可变性和值语义进行了优化,可用于数据传输对象 (DTO)。

public record RecordPoint(int X, int Y) // Record class with constructor  
{  
    public override string ToString() => $"({X}, {Y})";  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        RecordPoint point1 = new RecordPoint(5, 10);  
        Console.WriteLine(point1); // Output: (5, 10)  
  
        // Record classes are immutable (cannot modify after creation)  
        // point1.X = 15; // Compiler error!  
  
        RecordPoint point2 = point1 with { X = 15 }; // Create a copy with modified X  
        Console.WriteLine(point2); // Output: (15, 10)  
    }  
}

该类是一个记录类,提供属性和可能的构造函数。默认情况下,记录类是不可变的,这意味着其数据在创建后无法更改。分配另一个变量将创建数据的新副本。

记录结构(不可变值类型)

类似于 record 类,但是一种值类型,为小型数据结构提供更好的性能。

public record struct StructPoint(int X, int Y) // Record struct with constructor  
{  
    public override string ToString() => $"({X}, {Y})";  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        StructPoint point1 = new StructPoint(5, 10);  
        Console.WriteLine(point1); // Output: (5, 10)  
  
        // Record structs are immutable (cannot modify after creation)  
        // point1.X = 15; // Compiler error!  
  
        StructPoint point2 = point1 with { X = 15 }; // Create a copy with modified X  
        Console.WriteLine(point2); // Output: (15, 10)  
    }  
}

该类是一个记录结构体,提供存储在堆栈上的属性和可能的构造函数。当分配或传递时,将创建记录结构的副本。

高级类概念

按结构

分部类(拆分为多个代码文件)

一个类可以拆分为多个代码文件,从而促进大型类更好的组织和可维护性。

// LargeClass.cs  
public partial class LargeClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Method 1 from LargeClass");  
    }  
}// LargeClass_Part2.cs  
public partial class LargeClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Method 2 from LargeClass_Part2");  
    }  
}// Program.cs  
public static class Program  
{  
    public static void Main()  
    {  
        LargeClass largeClass = new LargeClass();  
        largeClass.Method1(); // Output: Method 1 from LargeClass  
        largeClass.Method2(); // Output: Method 2 from LargeClass\_Part2  
    }  
}

该类在两个单独的文件 ( 和 ) 中定义,演示了分部类的概念。

通过创建

匿名类(一次性定义和实例化)

同时定义和实例化的类,通常用于临时对象或在短时间内需要特定功能时。

public static void RunAnonymousClassExample()  
{  
    var temporaryObject = new { Name = "Temp Niraj", Value = 10 };  
    Console.WriteLine($"Name: {temporaryObject.Name}, Value: {temporaryObject.Value}");  
    // Output: Name: Temp Niraj, Value: 10  
}

该方法演示如何创建和使用匿名类。匿名类对于生存期较短的对象非常有用,在这些对象中,定义命名类可能有点矫枉过正。

选择正确的类型

了解这些类类型有助于您在设计 C# 应用程序时做出明智的决策。

以下是一些指导原则:

  • 对频繁修改的复杂对象使用引用类型。
  • 对于性能至关重要的简单数据结构,尝试使用值类型。
  • 选择继承以实现代码的可重用性,并在相关类之间强制执行一致性。
  • 利用密封类进行最终实现。
  • 为实用程序函数或常量选择静态类。
  • 使用嵌套类来实现帮助程序功能或与外部类的紧密耦合。
  • 考虑不可变数据传输对象的记录类。
  • 尝试使用小的、不可变的值类型的记录结构。
  • 利用部分班级来更好地组织大型班级。
  • 对于具有特定功能的临时对象,请谨慎使用匿名类。

结论

通过掌握这些类类型和概念,您将能够很好地在 C#/.NET 中创建健壮、可维护且结构良好的面向对象的程序。

阅读排行