我有一个像这样的C#API:
Task<T> Foo(serverUri)
我们说我有4个可能的服务器。我想实现一个将返回DiscUnionBar类型的函数:
type DiscUnionBar of T =
Safe of T | Weak of T | ConnectionError
实施将具有以下要求:
这很容易做到,因为我不能使用F#的异步并且必须坚持使用C#的任务用法吗?我在这一点上有点迷失。
答案 0 :(得分:6)
除非有理由不能在代码中使用Async
,否则唯一的限制是Foo
必须返回Task
,将调用Task
产生的Foo
转换为Async
Foo
应该没有问题。
这样你就可以使用F#的异步计算表达式来构建逻辑,好像Async
返回了let simpleComputation serverUri = async {
let! fooResult = Foo(serverUri) |> Async.AwaitTask
(* here you can work with the T returned by Foo's task *)
}
Task
我对Async.AwaitTask
库也有很好的使用经验,可以直接在异步计算表达式中使用AwaitTask
,而不必明确调用type
TClientConnection = class(TIdServerContext)
public
Cache: TIdThreadSafeStringList;
uuid: string; // or TGuid or whatever you are using...
ForceDisconnect: Boolean; // <-- add this
end;
...
var
List: TList; // or TIdContextList in modern Indy versions
I: Integer;
Client: TClientConnection;
begin
List := Server.Contexts.LockList;
try
for I := 0 to List.Count - 1 do
begin
Client := TClientConnection(TIdContext(List.Items[I]));
if Client.uuid = idtodiscnnect then
begin
Client.ForceDisconnect := True; // <-- don't actually disconnect here, just signal it
Break;
end;
end;
finally
Server.Contexts.UnlockList;
end;
end;
...
procedure TMyForm.ServerConnect(AContext: TIdContext);
begin
(AContext as TClientConnection).LastSendRecv := Ticks64;
AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
AContext.Connection.IOHandler.ReadTimeout := 30000;
end;
procedure TMyForm.ServerExecute(AContext: TIdContext);
var
Client: TClientConnection;
CMD: String;
Cache, OutboundCmds: TStringList;
I: integer;
Len: Integer;
begin
Client := AContext as TClientConnection;
if Client.ForceDisconnect then // <-- do the actual disconnect here
begin
AContext.Connection.Disconnect;
Exit;
end;
Len := AContext.Connection.IOHandler.InputBuffer.Size;
if Len >= 200000 then
begin
AContext.Connection.Disconnect;
Exit;
end;
// check for pending outbound commands...
OutboundCmds := nil;
try
Cache := Connection.OutboundCache.Lock;
try
if Cache.Count > 0 then
begin
OutboundCmds := TStringList.Create;
OutboundCmds.Assign(Cache);
Cache.Clear;
end;
finally
Connection.OutboundCache.Unlock;
end;
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
if Client.ForceDisconnect then // <-- and here, for good measure
begin
AContext.Connection.Disconnect;
Exit;
end;
AContext.Connection.IOHandler.WriteLn(OutboundCmds.Strings[I]);
end;
Connection.LastSendRecv := Ticks64;
end;
finally
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
OutboundCmds.Objects[I].Free;
end;
end;
OutboundCmds.Free;
end;
// check for a pending inbound command...
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
// if the client wants to stay connected, it should
// send a command every so often...
if GetElapsedTicks(Client.LastSendRecv) >= 30000 then
begin
AContext.Connection.Disconnect;
Exit;
end;
end;
end;
CMD := AContext.Connection.IOHandler.ReadLn;
Client.LastSendRecv := Ticks64;
...
end;
,并且可以帮助实现异步/任务互操作一般。虽然有些人可能不喜欢它试图隐藏任务。