【DryIOC】瞬态服务(Reuse.Transient Service)

DryIOC支持多种状态的Service,瞬态服务(Reuse.Transient Service)仅是其中一种。意味着该服务不会被重用。调用Resove方法或者注入时,都会重新创建一个服务实例。当你在注册服务时省略reuse参数或者没有改变容器的 Container.Rules.DefaultReuse属性,瞬态服务是容器的默认状态。

container.Register<IFoo, Foo>(Reuse.Transient);
container.Register<IFoo, Foo>();

1. 实现IDisposable接口的瞬态服务

当您注册的服务实现了IDispoable接口,该瞬态服务的释放职责将编程一个问题。这需要分成两种情况进行讨论。

1.1 通过Resolve方法获取瞬态服务实例

注意
DryIOC默认情况下不支持实现IDispoable接口的瞬态服务的注册。可通过以下两种方式就行配置以实现支持:

  • 在调用注册函数时,设置allowDisposableTransient: true。这种方式仅影响当前注册的服务
  • 在创建容器时使用Rules.WithoutThrowOnRegisteringDisposableTransient() 修改容器规则。这种方式是全局的

产生问题的原因
如果允许注册实现了IDisposable接口的服务,那么需要开发者自行管理创建的瞬态服务实例的释放工作。

// 定义容器变量
Container container;
// 指示是否通过全局方式允许容器支持实现`IDisposable`接口的瞬态服务
bool isUseGlobelFlag = false;

void Main()
{
	System.Console.WriteLine("容器创建");
	if (isUseGlobelFlag)
		container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
	else
		container = new Container();
	
	// 执行方法
	DisposableTransientService();
	
	System.Console.WriteLine("容器释放");
	container.Dispose();
	
	System.Console.WriteLine("程序结束");
}


void DisposableTransientService()
{
	System.Console.WriteLine("服务注册");
	if (isUseGlobelFlag)
		container.Register<X>();
	else
		container.Register<X>(setup:Setup.With(allowDisposableTransient:true));
	
	System.Console.WriteLine("服务解析");

	var x = container.Resolve<X>();
	x.Dispose();
}

class X : System.IDisposable
{
	public X()
	{
		System.Console.WriteLine(nameof(X) + " is created.");
	}

	public void Dispose()
	{
		System.Console.WriteLine(nameof(X) + " is disposed.");
	}
}

容器创建
服务注册
服务解析
X is created.
X is disposed.
容器释放
程序结束

上述程序的运行结果不会出现任何问题,因为我们可以手动的对瞬态服务的实例进行释放。如果注释DisposableTransientService方法种的x.Dispose();语句,运行后可以发现,x的释放工作将不被执行。这也从侧面验证了当允许容器注册实现了IDispoable接口的瞬态服务,瞬态服务实例的释放将不被执行

容器创建
服务注册
服务解析
X is created.
容器释放
程序结束

1.2 通过注入的方式获取瞬态服务实例

// 定义容器变量
Container container;
// 指示是否通过全局方式允许容器支持实现`IDisposable`接口的瞬态服务
bool isUseGlobelFlag = false;

void Main()
{
	System.Console.WriteLine("容器创建");
	if (isUseGlobelFlag)
		container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
	else
		container = new Container();
	
	// 执行方法
	DisposableTransientService();
	
	System.Console.WriteLine("容器释放");
	container.Dispose();
	
	System.Console.WriteLine("程序结束");
}


void DisposableTransientService()
{
	System.Console.WriteLine("服务注册");
	if (isUseGlobelFlag)
		container.Register<X>();
	else
		container.Register<X>(setup:Setup.With(allowDisposableTransient:true));		
	container.Register<XUser>();
	
	System.Console.WriteLine("服务解析");

	var user = container.Resolve<XUser>();
}

class X : System.IDisposable
{
	public X()
	{
		System.Console.WriteLine(nameof(X) + " is created.");
	}

	public void Dispose()
	{
		System.Console.WriteLine(nameof(X) + " is disposed.");
	}
}

class XUser
{
	public XUser(X x)
	{
		System.Console.WriteLine(nameof(XUser) + " is created.");
	}
}

容器创建
服务注册
服务解析
X is created.
XUser is created.
容器释放
程序结束

这里实现IDisposable接口的瞬态服务被作为XUser类构造函数的一个依赖。这种情况下,我们无法获得X类型的注入实例,也就无法手动进行释放。从而导致释放的问题。

2. 实现IDisposable接口的瞬态服务的跟踪

为了解决上述问题,DryIOC提供了一种机制对注入的瞬态服务进行跟踪,以便在适当的时候进行释放。

// 定义容器变量
Container container;
// 指示是否通过全局方式跟踪实现`IDisposable`接口的瞬态服务
bool isUseGlobelTrack = false;

void Main()
{
	System.Console.WriteLine("容器创建");
	if (isUseGlobelTrack)
		container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient().WithTrackingDisposableTransients());
	else
		container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
	
	// 执行方法
	DisposableTransientService();
	
	System.Console.WriteLine("容器释放");
	container.Dispose();
	
	System.Console.WriteLine("程序结束");
}


void DisposableTransientService()
{
	System.Console.WriteLine("服务注册");
	if (isUseGlobelTrack)
		container.Register<X>();
	else
		container.Register<X>(setup:Setup.With(trackDisposableTransient:true));		
	container.Register<XUser>();
	
	System.Console.WriteLine("服务解析");

	var user = container.Resolve<XUser>();
}

class X : System.IDisposable
{
	public X()
	{
		System.Console.WriteLine(nameof(X) + " is created.");
	}

	public void Dispose()
	{
		System.Console.WriteLine(nameof(X) + " is disposed.");
	}
}

class XUser
{
	public XUser(X x)
	{
		System.Console.WriteLine(nameof(XUser) + " is created.");
	}
}

容器创建
服务注册
服务解析
X is created.
XUser is created.
容器释放
X is disposed.
程序结束

由结果可以看出,瞬态服务释放的问题得到解决。

3. 阻止瞬态服务的跟踪

3.1 方式一:指定preventDisposal=true

// 定义容器变量
Container container;

void Main()
{
	System.Console.WriteLine("容器创建");
	container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient().WithTrackingDisposableTransients());
	
	// 执行方法
	DisposableTransientService();
	
	System.Console.WriteLine("容器释放");
	container.Dispose();
	
	System.Console.WriteLine("程序结束");
}


void DisposableTransientService()
{
	System.Console.WriteLine("服务注册");
	container.Register<X>(setup:Setup.With(preventDisposal:true));
	container.Register<XUser>();
	
	System.Console.WriteLine("服务解析");

	var user = container.Resolve<XUser>();
}

class X : System.IDisposable
{
	public X()
	{
		System.Console.WriteLine(nameof(X) + " is created.");
	}

	public void Dispose()
	{
		System.Console.WriteLine(nameof(X) + " is disposed.");
	}
}

class XUser
{
	public XUser(X x)
	{
		System.Console.WriteLine(nameof(XUser) + " is created.");
	}
}

容器创建
服务注册
服务解析
X is created.
XUser is created.
容器释放
程序结束

3.2 方式二:使用Func

// 定义容器变量
Container container;
XFactory xf;
static X xGlobal;
void Main()
{
	System.Console.WriteLine("容器创建");
	container = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient().WithTrackingDisposableTransients());
	
	// 执行方法
	DisposableTransientService();
	
	System.Console.WriteLine("容器释放");
	container.Dispose();
	
	// 获取时创建一个心的X
	var xx = xf.GetX();
	Console.WriteLine(xx == xf.X);
	System.Console.WriteLine("程序结束");
}


void DisposableTransientService()
{
	System.Console.WriteLine("服务注册");
	container.Register<X>();
	container.Register<XFactory>();
	
	System.Console.WriteLine("服务解析");

	Console.WriteLine("=========================");
	xf = container.Resolve<XFactory>();
}

class X : System.IDisposable
{
	public X()
	{
		System.Console.WriteLine(nameof(X) + " is created.");
	}

	public void Dispose()
	{
		System.Console.WriteLine(nameof(X) + " is disposed.");
	}
}

class XFactory
{
	public readonly Func<X> GetX;
	public readonly X X;
	
	// 注入x时创建一个X
	public XFactory(Func<X> getX, X x)
	{
		Console.WriteLine("=========================");
		xGlobal = x;
		this.X = x;
		this.GetX = getX;
		System.Console.WriteLine(nameof(XFactory) + " is created.");
	}
}

容器创建
服务注册
服务解析
=========================
X is created.
=========================
XFactory is created.
容器释放
X is disposed.
X is created.
False
程序结束

在构造XFactory时通过构造函数的参数x完成了一次注入,此时创建了一个X的实例。该实例在容器给释放时被释放。指定var xx = xf.GetX();语句时重新创建了一个X的实例。两次创建的实例不相同。

4. 使用其他默认reuse代替瞬态服务

void Main()
{
	var container = new Container(rules => rules.WithDefaultReuse(Reuse.Scoped));

	container.Register<Abc>();

	using (var scope = container.OpenScope())
	{
		var abc = scope.Resolve<Abc>();
		Console.WriteLine(abc == scope.Resolve<Abc>());
	}
}

class Abc { }

True

在同一个Scope中创建的实例是相同的.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]中的代码展示了如何使用`tf.Variable_scope`进行变量的复用。通过设置`reuse=tf.AUTO_REUSE`参数,可以在变量作用域内复用已经存在的变量。在代码中,使用`tf.get_variable`函数来获取变量,如果变量已经存在,则直接复用,否则创建新的变量。 引用\[2\]中的错误提示说明了在使用`reuse=True`时可能会出现的问题。当计算图中的节点已经存在时,再次创建同名节点会导致错误。正确的操作是对计算图进行复用,而不是直接使用`reuse=True`。 引用\[3\]中的错误提示说明了在首次调用计算图时,计算图并不存在,因此会产生错误。为了解决这个问题,可以在变量作用域中设置`reuse=tf.AUTO_REUSE`参数。 综上所述,`tf.AUTO_REUSE`是一种自动复用变量的机制,可以在变量作用域内复用已经存在的变量,避免重复创建同名变量导致的错误。 #### 引用[.reference_title] - *1* [tf.AUTO_REUSE作用](https://blog.csdn.net/qq_35203425/article/details/82469348)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Tensorflow复用计算图 reuse=tf.AUTO_REUSE](https://blog.csdn.net/alan418/article/details/106022713)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值