C#通过PrivateObject测试包含返回参数的函数

本文介绍了如何在C#中利用PrivateObject进行单元测试,特别是针对包含返回参数的私有函数。通过创建delegate并结合PrivateObject.Invoke方法,可以有效地测试这类函数。文中以一个超过固定长度文件写数据的场景为例,说明如何获取数据长度和起始位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        写代码的一个好习惯是做好单元测试,不仅测试public类及函数,有时候还需要测试private的类及函数,通过.Net单元测试自带的PrivateObject类可以实现,方法很简单,测试函数通过PrivateObject.Invoke,测试属性或变量通过PrivateObject.SetFieldOrProperty即可。但是,如果测试包含返回参数的函数就没法直接通过PrivateObject.Invoke函数,而是通过声明delegate的方式来实现。
        例如,需要向某个固定长度的文件写数据,超过限定长度后循环写数据,写完数据后需要获得当前数据长度,起始数据所在位置,除Write函数自身返回数据长度,还需要通过参数返回起始数据所在位置,请看参考代码.

        delegate int WriteDeletate(byte[] data, ref int offset);
<think>在C#中,私有构造函数通常用于特定的设计模式或场景。常见的用法包括:1.单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。 2.静态工具类:当类只包含静态成员时,防止实例化。3.工厂模式:通过工厂方法控制实例的创建。4.阻止直接实例化:强制使用工厂方法或嵌套类来创建对象。 5.实现不可变对象的构建器模式(BuilderPattern)。下面我将通过几个示例来展示这些常见用法。###1.单例模式(Singleton)单例模式确保一个类只有一个实例,并提供一个全局访问点。```csharppublic classSingleton{//私有静态变量,持有唯一的实例privatestatic Singleton_instance;//私有构造函数,防止外部使用new创建实例private Singleton(){//初始化代码}//公共静态方法,提供全局访问点public staticSingleton Instance{get{if(_instance== null){_instance= newSingleton();}return_instance;}}//示例方法publicvoid DoSomething(){Console.WriteLine("Singleton isdoing something.");} }//使用方式:Singleton singleton= Singleton.Instance;singleton.DoSomething();``` **注意**:上述代码不是线程安全的。在多线程环境下,可以使用双重锁定或静态初始化来实现线程安全。 ###2.静态工具类当类只包含静态成员时,可以使用私有构造函数来防止实例化。```csharppublic staticclass MathUtility{//私有构造函数,防止实例化privateMathUtility(){//不需要实例化}publicstatic intAdd(inta,int b){return a+ b;}public staticint Multiply(int a, intb){returna *b;}} //使用方式:int sum= MathUtility.Add(3,5);int product= MathUtility.Multiply(3,5);``` ###3.工厂模式通过工厂方法创建对象,构造函数私有,这样外部只能通过工厂方法获取实例。```csharppublic classProduct{//私有构造函数private Product(){}//工厂方法public staticProduct CreateProduct(){return newProduct();}publicvoid Operation(){Console.WriteLine("Productoperation.");}} //使用方式:Product product= Product.CreateProduct(); product.Operation(); ```###4.构建器模式(BuilderPattern)用于创建复杂对象,特别是当对象有很多可选参数时。```csharppublic classPizza{public stringSize {get;private set; }publicbool Cheese{ get; privateset;}public boolPepperoni{ get; privateset;}public boolBacon {get;private set; }//私有构造函数,只能通过Builder创建private Pizza(PizzaBuilderbuilder){Size= builder.Size;Cheese= builder.Cheese;Pepperoni =builder.Pepperoni;Bacon= builder.Bacon;}//构建器类publicclass PizzaBuilder{publicstring Size{ get; set; }publicbool Cheese{ get; set; }publicbool Pepperoni {get;set;}public boolBacon {get;set;}public PizzaBuilder(stringsize){Size= size;}public PizzaBuilder AddCheese(){Cheese= true;return this;}public PizzaBuilder AddPepperoni(){Pepperoni= true;return this;}public PizzaBuilder AddBacon(){Bacon =true;returnthis;}publicPizza Build(){return newPizza(this);}} }//使用方式: Pizza pizza= newPizza.PizzaBuilder("Large").AddCheese().AddPepperoni().Build();``` ###5.防止直接实例化,强制使用工厂方法有时,我们希望对对象的创建有更多的控制,例如在创建对象之前进行一些验证。```csharppublic classStudent{public stringName {get;private set; }publicint Age{ get; privateset;}//私有构造函数private Student(string name, intage){Name= name;Age =age;}//工厂方法,可以在此处添加验证逻辑publicstatic StudentCreateStudent(string name, intage){if(string.IsNullOrEmpty(name))thrownew ArgumentException("Name cannotbe empty");if (age <0)throw newArgumentException("Agecannot benegative");returnnew Student(name,age);}} //使用方式:Student student= Student.CreateStudent("Alice",20);``` ###总结私有构造函数C#中是一种强大的工具,用于控制对象的创建。通过将构造函数设为私有,我们可以: -实现单例模式,确保只有一个实例。-创建静态工具类,防止不必要的实例化。 -使用工厂方法或构建器模式来控制对象的创建过程,增加灵活性和可维护性。 -在创建对象时添加验证逻辑。 §§相关问题§§: 1.如何在C#中实现线程安全的单例模式?2.工厂模式和构建器模式的主要区别是什么? 3.在C#中,如何防止一个类被继承?4.如何使用私有构造函数来实现依赖注入?</think>### C# 私有构造函数的常见用法详解 私有构造函数C#中有多种重要应用场景,以下是五种最常见的使用模式及其完整实现: #### 1. 单例模式(Singleton) 确保类只有一个实例并提供全局访问点 ```csharp public class ApplicationLogger { // 私有静态实例 private static readonly Lazy<ApplicationLogger> _instance = new Lazy<ApplicationLogger>(() => new ApplicationLogger()); // 私有构造函数 private ApplicationLogger() { Console.WriteLine("日志系统初始化完成"); } // 公共访问点 public static ApplicationLogger Instance => _instance.Value; public void Log(string message) { Console.WriteLine($"[{DateTime.Now}] {message}"); } } // 使用示例 var logger = ApplicationLogger.Instance; logger.Log("应用程序启动"); logger.Log("用户登录成功"); ``` #### 2. 静态工具类(Static Utility Class) 防止实例化只包含静态方法的类 ```csharp public sealed class MathHelper { // 私有构造函数阻止实例化 private MathHelper() { throw new InvalidOperationException("工具类不应被实例化"); } public static double CalculateCircleArea(double radius) { return Math.PI * Math.Pow(radius, 2); } public static double CalculateHypotenuse(double a, double b) { return Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2)); } } // 使用示例 double area = MathHelper.CalculateCircleArea(5); Console.WriteLine($"圆面积: {area:F2}"); double hypotenuse = MathHelper.CalculateHypotenuse(3, 4); Console.WriteLine($"斜边长度: {hypotenuse}"); ``` #### 3. 工厂模式(Factory Pattern) 控制对象创建过程,封装实例化逻辑 ```csharp public class PaymentProcessorFactory { // 私有构造函数 private PaymentProcessorFactory() { } public static IPaymentProcessor CreateProcessor(string paymentType) { return paymentType.ToLower() switch { "creditcard" => new CreditCardProcessor(), "paypal" => new PayPalProcessor(), "alipay" => new AlipayProcessor(), _ => throw new ArgumentException("不支持的支付方式") }; } } public interface IPaymentProcessor { void ProcessPayment(decimal amount); } // 具体实现类 internal class CreditCardProcessor : IPaymentProcessor { public void ProcessPayment(decimal amount) { Console.WriteLine($"信用卡支付 {amount:C} 处理中..."); } } // 使用示例 var processor = PaymentProcessorFactory.CreateProcessor("CreditCard"); processor.ProcessPayment(150.99m); ``` #### 4. 对象池模式(Object Pooling) 管理可重用对象集合,减少资源开销 ```csharp public class DatabaseConnectionPool { private const int POOL_SIZE = 5; private readonly Queue<DbConnection> _available = new(); private readonly List<DbConnection> _inUse = new(); // 私有构造函数 private DatabaseConnectionPool(string connectionString) { for (int i = 0; i < POOL_SIZE; i++) { var conn = new SqlConnection(connectionString); conn.Open(); _available.Enqueue(conn); } } // 单例访问 private static Lazy<DatabaseConnectionPool> _instance; public static void Initialize(string connectionString) { _instance = new Lazy<DatabaseConnectionPool>(() => new DatabaseConnectionPool(connectionString)); } public static DatabaseConnectionPool Instance => _instance?.Value ?? throw new InvalidOperationException("连接池未初始化"); // 获取连接 public DbConnection AcquireConnection() { lock (_available) { if (_available.Count == 0) throw new TimeoutException("无可用连接"); var conn = _available.Dequeue(); _inUse.Add(conn); return conn; } } // 释放连接 public void ReleaseConnection(DbConnection conn) { lock (_available) { if (_inUse.Contains(conn)) { _inUse.Remove(conn); _available.Enqueue(conn); } } } } // 使用示例 DatabaseConnectionPool.Initialize("Server=..."); var pool = DatabaseConnectionPool.Instance; using (var conn = pool.AcquireConnection()) { // 执行数据库操作 Console.WriteLine("使用数据库连接..."); } // 连接自动返回到池中 ``` #### 5. 不可变对象构建器(Immutable Object Builder) 创建不可变对象并提供流畅的构建接口 ```csharp public sealed class ConfigurationSettings { // 不可变属性 public string Server { get; } public int Port { get; } public int Timeout { get; } public bool UseSSL { get; } // 私有构造函数 private ConfigurationSettings(string server, int port, int timeout, bool useSsl) { Server = server; Port = port; Timeout = timeout; UseSSL = useSsl; } // 构建器类 public class Builder { private string _server = "localhost"; private int _port = 8080; private int _timeout = 30; private bool _useSsl; public Builder WithServer(string server) { _server = server ?? throw new ArgumentNullException(nameof(server)); return this; } public Builder WithPort(int port) { if (port < 1 || port > 65535) throw new ArgumentOutOfRangeException(nameof(port)); _port = port; return this; } public Builder WithTimeout(int seconds) { if (seconds < 1) throw new ArgumentException("超时时间必须大于0"); _timeout = seconds; return this; } public Builder EnableSSL() { _useSsl = true; return this; } public ConfigurationSettings Build() { return new ConfigurationSettings(_server, _port, _timeout, _useSsl); } } } // 使用示例 var config = new ConfigurationSettings.Builder() .WithServer("api.example.com") .WithPort(443) .WithTimeout(60) .EnableSSL() .Build(); Console.WriteLine($"配置: {config.Server}:{config.Port}, SSL: {config.UseSSL}"); ``` ### 特殊场景补充 #### 6. 依赖注入支持 在DI容器中注册需要私有构造函数的类型 ```csharp // 服务类 public class ReportGenerator { private readonly IDataService _dataService; // 私有构造函数 private ReportGenerator(IDataService dataService) { _dataService = dataService; } // 工厂方法用于DI注册 public static ReportGenerator Create(IServiceProvider provider) { var service = provider.GetRequiredService<IDataService>(); return new ReportGenerator(service); } public void GenerateReport() { var data = _dataService.GetReportData(); // 生成报告... } } // DI注册 services.AddScoped<IDataService, SqlDataService>(); services.AddScoped<ReportGenerator>(provider => ReportGenerator.Create(provider)); ``` #### 7. 反序列化支持 使用私有构造函数处理JSON反序列化 ```csharp public class UserProfile { public int UserId { get; } public string Username { get; } public DateTime CreatedDate { get; } [JsonConstructor] // JSON.NET特性 private UserProfile(int userId, string username, DateTime createdDate) { UserId = userId; Username = username; CreatedDate = createdDate; } // 工厂方法 public static UserProfile Create(int id, string name) => new UserProfile(id, name, DateTime.UtcNow); } // 反序列化 var json = "{\"UserId\":123,\"Username\":\"john_doe\",\"CreatedDate\":\"2023-01-01T00:00:00Z\"}"; var user = JsonConvert.DeserializeObject<UserProfile>(json); ``` ### 设计原则总结 1. **控制实例化**:通过私有构造函数限制对象创建方式 2. **保证单一职责**:每个类/方法只负责一个功能 3. **提高可测试性**:通过工厂方法简化单元测试 4. **增强安全性**:防止非法状态的对象创建 5. **优化性能**:对象池减少资源开销
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值