如何避免一遍又一遍地创建同一个对象?

Dom*_*que 5 c# singleton static callstack scope

正如今天早上提到的,我继续研究我的 TCP 套接字。

我发现每次我通过这样的套接字发送消息时,套接字的数量都会不断增加。这仅仅意味着我不断创建和打开新的套接字,而不是重新使用已经打开的套接字。

在我的应用程序中,我有一个连接存储库,我只需要使用其中一个。但我担心我会不断地创造新的。这是它的完成方式:

public static class Repository
{
  ...
  public static Conn GetByName(string name, ...)
  {
    return result = 
      context.Set<Conn>().Where(o => o.Name == name).FirstOrDefault();
  }
}

...
Conn Connection_For_Message = Repository.GetByName(request.ConnectionName, ...);
Run Code Online (Sandbox Code Playgroud)

据我说:

  1. Repository声明 的事实static会导致在内部创建一个对象。
  2. 当该GetByName()方法执行某个FirstOrDefault()方法时Where(),这会给出已经存在的对象,并且不会创建新的对象。

现在我的印象是 1. 是正确的,但 2. 是错误的,因为Connection Connection_For_Message 总是创建一个对象的新实例。

我的印象是否正确?如果是,我该如何解决这个问题?我正在考虑Repository从静态类更改为单例,但我没有找到ISingleton或 中的东西System.Reflection,或者我正在寻找完全错误的方向?

编辑:这是该类构造函数的一部分Conn

public Conn(...)
{
    ...
    TcpConnection = new TcpConnection(...); // in here a 
    ...
}
Run Code Online (Sandbox Code Playgroud)

TcpConnection班级而言:

public class TcpConnection : IDisposable
{
    public Socket _socket;
    ...
Run Code Online (Sandbox Code Playgroud)

每次发送消息时,我都会传递该GetByName()方法,并且我的调用堆栈如下所示:

  My_Application.dll!TcpConnection.TcpConnection(...) Line 39   C#
> My_Application.dll!Conn.Conn(...) Line 32 C#
  [External Code]   
  My_Application.dll!ConnectionRepository.GetByName(string name, ...) Line 71   C#
Run Code Online (Sandbox Code Playgroud)

标记为>构造函数的行,这证明确实GetByName()正在调用Conn构造函数。GetByName()(哦,为什么方法和构造函数之间有“外部代码” ?)

再次编辑:我已成功显示外部代码,因此选中“显示外部代码”的调用堆栈:

>  My_Application.dll!TcpConnection.TcpConnection(...) Line 39  C#
   My_Application.dll!Conn.Conn(...) Line 32    C#
   [Native to Managed Transition]   
   [Managed to Native Transition]   
   System.Private.CoreLib.dll!System.Reflection.RuntimeConstructorInfo.Invoke(System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture)    C#
   System.Private.CoreLib.dll!System.RuntimeType.CreateInstanceImpl(System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture)   C#
   System.Private.CoreLib.dll!System.Activator.CreateInstance(System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes)    C#
   Castle.Core.dll!Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(System.Type proxyType, System.Collections.Generic.List<object> proxyArguments, System.Type classToProxy, object[] constructorArguments)  C#
   [Lightweight Function]   
   Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<Conn>.Enumerator.MoveNext()   C#
   System.Linq.dll!System.Linq.Enumerable.TryGetSingle<Conn>(System.Collections.Generic.IEnumerable<Conn> source, out bool found)   C#
   [Lightweight Function]   
   System.Linq.Queryable.dll!System.Linq.Queryable.FirstOrDefault<Conn>(System.Linq.IQueryable<Conn> source)    C#
   My_Application.dll!ConnectionRepository.GetByName(string name, ...) Line 71  C#
Run Code Online (Sandbox Code Playgroud)

Evk*_*Evk 6

您正在使用实体框架查询数据库以获取 Conn(正如我们从调用堆栈中看到的那样)。数据库当然不能存储TCP连接之类的东西。每次执行查询时,都会返回 Conn 的新实例(从技术上讲,它可以从缓存返回,但不会改变情况),尽管它代表相同的数据库行。在代表数据库条目的类的构造函数中创建 TCP 客户端并不是一个好主意。

相反,您可以使用ConcurrentDictionary<string, TcpConnection>线程安全的方式管理连接。