目前,我正在开发一个API,开发人员可以订阅它以了解更新。
所以现在我正在实现一个接口IResult
,这样我就可以在回调结果中发送不同的参数。现在的问题是,如果在将来,我想添加一个新的回调,我必须在方法中添加一个参数,开发人员还需要更改他们的方法调用。对此有一个很好的解决方案吗?
public interface IResult
{
int i { get; set; }
}
public class ConcreteResult : IResult
{
public int i
{
get;set;
}
}
public class MyAPI
{
public delegate void MyAPIDelegate(IResult result);
public void StartService(MyAPIDelegate callback, MyAPIDelegate callback2)
{
//step 1
int i = 0;
ConcreteResult result1 = new ConcreteResult();
result1.i = i;
callback(result1);
//step 2
i += 1;
ConcreteResult result2 = new ConcreteResult();
result2.i = i;
callback2(result2);
//potentially added in the future
//i += 1;
//callback3();
}
public void main()
{
//developers use my API
StartService(developerCallback, developerCallback2);
}
private void developerCallback(IResult result)
{
Console.WriteLine(result.i);
}
private void developerCallback2(IResult result)
{
Console.WriteLine(result.i);
}
}
答案 0 :(得分:1)
奇怪的是每个人都在推荐活动,但没有人展示一个例子。我咬了。
根据命名惯例来判断我猜你来自Java领域。 (C#方法一般是PascalCase)。 C#有events,这使得这样的事情变得更加简单。我建议你研究它们,因为它们在C#代码中很常见。
您所要做的就是在您的类上定义一个公共事件,并让该类在必要时调用该事件。 (执行?.
因为未订阅的事件非常奇怪。)
然后从使用消费类中,使用+=
订阅处理程序。
这使您可以在将来添加新活动,而无需消费者担心。
public class MyAPI
{
public event Action<IResult> Callback1;
public event Action<IResult> Callback2;
public void StartService()
{
//step 1
int i = 0;
ConcreteResult result1 = new ConcreteResult();
result1.i = i;
Callback1?.Invoke(result1);
//step 2
i += 1;
ConcreteResult result2 = new ConcreteResult();
result2.i = i;
Callback2?.Invoke(result2);
//potentially added in the future
//i += 1;
//callback3();
}
}
public static class Program {
public static void Main()
{
//developers use my API
var api = new MyAPI();
api.Callback1 += DeveloperCallback;
api.Callback2 += DeveloperCallback2;
api.StartService();
}
private static void DeveloperCallback(IResult result)
{
Console.WriteLine(result.i);
}
private static void DeveloperCallback2(IResult result)
{
Console.WriteLine(result.i);
}
}
对于简单的事件处理程序,您可以内联订阅:
api.Callback1 += result =>
{
Console.WriteLine(result.i);
};
甚至更简单的单行:
api.Callback1 += result => Console.WriteLine(result.i);
既然你问过,另一种选择比简单事件更重一些,但最终更强大的是Reactive Extensions。如果你想使用它们,那么你可以编写如下代码:
using System.Reactive.Subjects;
public class MyAPI
{
private readonly Subject<IResult> callback1 = new Subject<IResult>();
private readonly Subject<IResult> callback2 = new Subject<IResult>();
public void StartService()
{
//step 1
int i = 0;
ConcreteResult result1 = new ConcreteResult();
result1.i = i;
callback1.OnNext(result1);
//step 2
i += 1;
ConcreteResult result2 = new ConcreteResult();
result2.i = i;
callback2.OnNext(result2);
}
public IObservable<IResult> Callback1 => this.callback1;
public IObservable<IResult> Callback2 => this.callback2;
}
public static class Program
{
public static void Main()
{
var api = new MyAPI();
// Subscribing returns a disposable subscription, and disposing it unsubscribes.
// That means you can use lambda syntax and still unsubscribe later
IDisposable subscription =
api.Callback1.Subscribe(result => Console.WriteLine(result.i));
api.StartService(); // Writes result.
// Once disposed, event is no longer called
subscription.Dispose();
api.StartService(); // Doesn't write result.
// Since IDisposable is a special thing that can be scoped to using blocks in C#, you can do the following:
using (api.Callback1.Subscribe(result => Console.WriteLine(result.i)))
{
api.StartService(); // Writes result
}
api.StartService(); // Doesn't write result
}
}
答案 1 :(得分:0)
我强烈建议您使用@Vikhram建议的事件,但这是您的示例,修改为使用您请求的类。
请注意,在调用函数时我没有指定Callback3
。 API会在调用它时使用.?
,而不仅仅是.
,因此如果开发人员没有通过NullReferenceException
,它就不会导致MyCallbackInfo
。
当您添加更多回调时,只需向public interface IResult {... }
public class ConcreteResult : IResult {...}
public class MyStartServiceCallbackInfo
{
public MyAPI.MyAPIDelegate Callback1 { get; set; }
public MyAPI.MyAPIDelegate Callback2 { get; set; }
public MyAPI.MyAPIDelegate Callback3 { get; set; }
}
public class MyAPI
{
public delegate void MyAPIDelegate(IResult result);
public void StartService(MyStartServiceCallbackInfo callbacks)
{
...
callbacks?.Callback1(result1);
...
callbacks?.Callback2(result2);
...
callbacks?.Callback3(result3);
}
public void main()
{
StartService(new MyCallbackInfo()
{
Callback1 = developerCallback,
Callback2 = developerCallback2,
});
}
private void developerCallback(IResult result)
{
Console.WriteLine(result.i);
}
private void developerCallback2(IResult result)
{
Console.WriteLine(result.i);
}
}
添加其他属性,并调用它们与现有属性相同。
""