C# 如何避免仅用于依赖项注入的未使用字段?
好吧,从技术上讲,它们不是“未使用的”,但它们从未被持有它们的类使用过,所以我猜在某种意义上它们是。这是一个假设的情况,我正试图找到答案 我有一个类C# 如何避免仅用于依赖项注入的未使用字段?,c#,C#,好吧,从技术上讲,它们不是“未使用的”,但它们从未被持有它们的类使用过,所以我猜在某种意义上它们是。这是一个假设的情况,我正试图找到答案 我有一个类NetworkListener public NetworkListener(IPAddress ipAddress, int port, NetworkClientPacketRepository packetRepository) NetworkListener有时必须创建一个新类,该类位于合成根目录之外: new NetworkClient(
NetworkListener
public NetworkListener(IPAddress ipAddress, int port, NetworkClientPacketRepository packetRepository)
NetworkListener有时必须创建一个新类,该类位于合成根目录之外:
new NetworkClient(await _listener.AcceptTcpClientAsync(), _packetRepository, _logger);
services.AddSingleton<NetworkEventArguments>();
services.AddSingleton<NetworkClientRepository>();
services.AddSingleton<Dictionary<int, IClientPacket>>();
services.AddSingleton<ClientPacketRepository>();
services.AddSingleton(provider => new NetworkListener(
IPAddress.Parse(config.GetValue<string>("Networking:Host")),
config.GetValue<int>("Networking:Port"),
provider.GetService<NetworkClientRepository>()
));
这是坏习惯吗?感觉是这样,看起来是这样,所以一定是这样,对吧?我不确定
有几件事对我来说很突出,表明它是
A.NetworkListener必须接受NetworkClientRepository
依赖项,因为NetworkClient
需要它
B.NetworkListener必须接受记录器
依赖项,因为NetworkClient
需要它
这似乎是错误的,但我不知道更好的方法,因此我为什么这样做
如何避免将未使用的字段传递到子类
这是我的作文根:
new NetworkClient(await _listener.AcceptTcpClientAsync(), _packetRepository, _logger);
services.AddSingleton<NetworkEventArguments>();
services.AddSingleton<NetworkClientRepository>();
services.AddSingleton<Dictionary<int, IClientPacket>>();
services.AddSingleton<ClientPacketRepository>();
services.AddSingleton(provider => new NetworkListener(
IPAddress.Parse(config.GetValue<string>("Networking:Host")),
config.GetValue<int>("Networking:Port"),
provider.GetService<NetworkClientRepository>()
));
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton(provider=>newNetworkListener(
IPAddress.Parse(config.GetValue(“Networking:Host”),
config.GetValue(“网络:端口”),
provider.GetService()
));
NetworkListener类:
public class NetworkListener : IDisposable
{
private readonly NetworkClientRepository _clientRepository;
private readonly ClientPacketRepository _packetRepository;
private readonly TcpListener _listener;
public NetworkListener(IPAddress ipAddress, int port, NetworkClientRepository clientRepository, ClientPacketRepository packetRepository)
{
_clientRepository = clientRepository;
_packetRepository = packetRepository;
_listener = new TcpListener(ipAddress, port);
}
public void Start(int backlog = 100)
{
_listener.Start(backlog);
}
public async Task ListenAsync()
{
while (true)
{
HandleIncomingConnection(await _listener.AcceptTcpClientAsync());
}
}
public event EventHandler<NetworkEventArguments> ClientConnected;
private void HandleIncomingConnection(TcpClient client)
{
var networkClient = new NetworkClient(client, _packetRepository);
_clientRepository.AddClient(networkClient);
ClientConnected?.Invoke(this, new NetworkEventArguments
{
Client = networkClient
});
}
public void Dispose()
{
_listener.Server.Close();
_listener.Server.Dispose();
}
}
公共类NetworkListener:IDisposable
{
专用只读网络clientRepository\u clientRepository;
专用只读客户端packetRepository _packetRepository;
专用只读TcpListener\u侦听器;
公用网络侦听器(IPAddress IPAddress、int端口、NetworkClientRepository clientRepository、ClientPacketRepository packetRepository)
{
_clientRepository=clientRepository;
_packetRepository=packetRepository;
_侦听器=新的TcpListener(IP地址,端口);
}
公共void开始(int backlog=100)
{
_listener.Start(backlog);
}
公共异步任务ListenAsync()
{
while(true)
{
HandleIncomingConnection(wait_listener.AcceptCpclientAsync());
}
}
公共事件事件处理程序ClientConnected;
私有无效HandleIncomingConnection(TcpClient客户端)
{
var networkClient=新的networkClient(客户端,_packetRepository);
_clientRepository.AddClient(networkClient);
ClientConnected?.Invoke(此,新的NetworkEventArguments)
{
客户端=网络客户端
});
}
公共空间处置()
{
_listener.Server.Close();
_Dispose();
}
}
NetworkClient类:
public class NetworkClient : IDisposable
{
public TcpClient TcpClient { get; }
private readonly ClientPacketRepository _packetRepository;
private readonly ILogger _logger;
private readonly NetworkStream _networkStream;
public NetworkClient(TcpClient tcpClient, ClientPacketRepository packetRepository, ILogger logger)
{
TcpClient = tcpClient;
_packetRepository = packetRepository;
_logger = logger.ForContext<NetworkClient>();
_networkStream = tcpClient.GetStream();
ProcessDataAsync();
}
private void ProcessDataAsync()
{
var thread = new Thread(() =>
{
// TODO: Read from tcpClient
});
thread.Start();
}
public void Dispose()
{
TcpClient.Dispose();
}
}
公共类网络客户端:IDisposable
{
公共TcpClient TcpClient{get;}
专用只读客户端packetRepository _packetRepository;
专用只读ILogger\u记录器;
专用只读网络流_NetworkStream;
公用网络客户端(TcpClient TcpClient、ClientPacketRepository packetRepository、ILogger记录器)
{
TcpClient=TcpClient;
_packetRepository=packetRepository;
_logger=logger.ForContext();
_networkStream=tcpClient.GetStream();
ProcessDataAsync();
}
私有void ProcessDataAsync()
{
变量线程=新线程(()=>
{
//TODO:从tcpClient读取
});
thread.Start();
}
公共空间处置()
{
TcpClient.Dispose();
}
}
这是坏习惯吗?感觉是这样,看起来是这样,所以一定是这样,对吧?我不确定
当然是这样。您的类应该只实例化不能注入的数据类或第三方服务。实例化TcpListener
就是后者的一个很好的例子
你的问题来自这里:
public NetworkClient(TcpClient tcpClient, ClientPacketRepository packetRepository, ILogger logger)
尽量避免在构造函数中将依赖项和“数据”混合在一起。相反,让构造函数只有可以注入的参数,并将其余参数放入适当的方法中
以下是NetworkClient
的外观:
public interface INetworkClient
{
void ProcessDataAsync(TcpClient tcpClient);
}
public class NetworkClient : INetworkClient, IDisposable
{
private readonly ClientPacketRepository _packetRepository;
private readonly ILogger _logger;
public NetworkClient(ClientPacketRepository packetRepository, ILogger logger)
{
_packetRepository = packetRepository;
_logger = logger.ForContext<NetworkClient>();
}
// this Async in the name and the Thread being created internally looks smelly
private void ProcessDataAsync(TcpClient tcpClient)
{
var networkStream = tcpClient.GetStream();
// ...
}
// ...
}
因此,您可以将其用于:
private void HandleIncomingConnection(TcpClient client)
{
var networkClient = _networkClientFactory.Create();
netowrkClient.ProcessDataAsync(client);
_clientRepository.AddClient(networkClient);
ClientConnected?.Invoke(this, new NetworkEventArguments
{
Client = networkClient
});
}
NetworkClient
对象何时创建?在构造函数期间或以后?它是在TcpListener有新的传入连接时创建的。@CamiloterienTo我使用的是Microsoft.Extensions.DependencyInjection
,但是NetworkClient
是一个临时的,在TcpListener有新连接时创建NetworkListener
在我的DI容器中。@Camilotervento我已经意识到,我的问题是如何避免这样做。你能编写一个NetworkClientFactory
来获取一个新的NetworkClient
对象吗?您可以注入此实例(已解决所有依赖项),因此不再需要ILogger
和NetworkClientRepository
引用。这似乎是在传播问题,而不是解决问题,工厂仍然需要以某种方式从DI容器中获取记录器实例。不是真的,工厂只需要从迪肯那里得到一个暂时的例子,你的答案中包括一个这样的例子吗?否则,我将陷入与以前相同的境地,不知道如何在类中实例化类,以及如何获取该类的依赖项,而不将它们存储在创建新类的类中。我正在使用Serilog。编辑了答案@aaabe,因为无法将来自\u listener.AcceptTcpClientAsync()
的TcpClient传入NetworkClient
的构造函数。我认为构建它就像返回新的NetworkClient(client,_serviceProvider.GetService(),_serviceProvider.GetService())
是唯一的选项,或者使用ActivatorUtilities获得更少的代码,但方法相同。