我正在开发一个库,我在寻找正确的API结构方面遇到了一些麻烦,这种API结构使代码保持高效,而不需要为每个可用的API提供大量不同的重载。
说我有这个方法:
public static Brush CreateDummyBrush(Color tint, float mix, float blur)
现在,我想让用户同时收到一个EffectAnimation
实例,用于那些色调和模糊动画,让他在将来为它们设置动画。假设EffectAnimation
只是一个delegate
,它在返回的Brush
上开始动画。完整的代码是here,以防万一。
public static Brush CreateDummyBrush(
Color tint, float mix, out EffectAnimation mixAnimation,
float blur, out EffectAnimation blurAnimation)
现在,如果用户想要为这两个动画接收delegate
,这是完全正常的。但是,假设我只需要设置模糊效果的动画,那么我就像这样调用这个API:
Brush brush = CreateDummyBrush(Colors.Gray, 0.6f, out _, 8, out var blurAnimation);
这是有效的,但是库最终会分配一个无用的delegate
,因为它只是被丢弃了。
快速解决方案是创建4个不同的重载,以涵盖out
参数的各种组合。但绝对不是正确的方法:太杂乱,如果我有3个out
参数,API的数量会变得太大。
所以我的问题是:调用者可以检查输入out
参数是否实际上是一个有效的引用,或者是否已使用丢弃标识符?我知道C#有很多隐藏的技巧和API,有什么东西可以实现这个目标吗?
非常感谢!
不完全是你想要的,但如果你想改变API以返回一个元组...
public (Brush, EffectAnimation, EffectAnimation) CreateDummyBrush(Color tint, float mix, float blur)
{
enter code here
}
//call it like so
var (brush, _, _) = CreateDummyBrush( tint, mix, blur);
var (brush, mixAnimation, _) = CreateDummyBrush( tint, mix, blur);
它不会保存函数内的处理来创建对象,但至少它们将是GC
对于少量可能的输出参数,我创建了一个Enum
和一个struct
:
[Flags]
public enum RequestedEffect {
None = 0,
Mix = 1,
Blur = 2,
DanceLightFandango = 4
}
public struct Effects {
public RequestedEffect Effect;
public EffectAnimation BlurEffect;
public EffectAnimation MixEffect;
public EffectAnimation DanceLightFanangoEffect;
}
然后,您将更改签名为:
public static Brush CreateDummyBrush(
Color tint, float mix, float blur,
ref Effects animations){...}
然后,如果对此结构进行任何初始化,则由调用者决定 - default(Effect)
意味着调用者不请求任何动画。您可能希望更改一些命名。
请注意,虽然在上面,Effects
中的所有非枚举字段都是相同的类型,但在使用此模式时不需要。