C# 将等待与动态类型一起使用时行为不一致
我试图使用C# 将等待与动态类型一起使用时行为不一致,c#,.net,async-await,C#,.net,Async Await,我试图使用动态来解决由于设计或缺乏设计而带来的不便(如果有兴趣,可以在这里找到“不便”) 简而言之,我需要返回实体实例的集合。类非常简单: [JsonObject] public class Entity { [PrimaryKey] [JsonProperty(PropertyName = "id")] public virtual int Id { get; set; } [JsonIgnore] public string Content { ge
动态来解决由于设计或缺乏设计而带来的不便(如果有兴趣,可以在这里找到“不便”)
简而言之,我需要返回实体
实例的集合。类非常简单:
[JsonObject]
public class Entity
{
[PrimaryKey]
[JsonProperty(PropertyName = "id")]
public virtual int Id { get; set; }
[JsonIgnore]
public string Content { get; set; }
}
所以实体
只有Id
和内容
。继承类可能有其他属性,但我只对内容部分(复杂JSON)感兴趣
可以通过generic存储库
访问各种不同的实体。我需要知道具体类的类型
,因为T
通过数据提供程序映射到底层SQLite表,该数据提供程序构建在SQLite net ORM之上
例如,如果我有Schedule:Entity
,那么我将使用Repository
操作名为Schedule
的表。这部分很好用
// must be instantiated with concrete class/type inheriting
// from Entity in order to map to correct database table
public class Repository<T> where T : new()
{
public async virtual Task<IEnumerable<T>> GetAllAsync()
{
return await SQLiteDataProvider.Connection.Table<T>().ToListAsync();
}
// etc.
}
因此,如果(上面)我使用blocking.Result
的话,一切都会很有魅力。相反,如果我使用wait
,代码可能工作,也可能不工作。这似乎真的取决于行星的位置和/或飞行的意大利面怪物的情绪波动
随机地,但更多的时候,给定的线会被抛出
无法强制转换类型为的对象
'System.Runtime.CompilerServices.TaskWaiter'1[System.Collections.Generic.IEnumerable'1[MyNamespace.Schedule]'
键入“System.Runtime.CompilerServices.INotifyCompletion”
我使用的是.NET 4.0扩展框架。如果存储库类型是您自己创建的类型,您可以让它基于具有抽象任务GetAllAsync()
的抽象基类型。然后,因为您的存储库显然已经有了该签名的方法,所以您很好:
public abstract class Repository
{
public abstract Task<IEnumerable<Entity>> GetAllAsync();
}
公共抽象类存储库
{
公共抽象任务GetAllAsync();
}
然后让您的存储库
基于存储库
public class Repository<T>: Repository where T: Entity // Your existing class
{
public override async Task<IEnumerable<Entity>> GetAllAsync()
{
// Your existing implementation
}
//...existing stuff...
}
public-class-Repository:Repository,其中T:Entity//您现有的类
{
公共重写异步任务GetAllAsync()
{
//您现有的实现
}
//…现有的东西。。。
}
然后,当使用它而不是动态时,您可以说:
public async Task<IEnumerable<Entity>> GetAllEntitiesFrom(CollectionArgs args)
{
var entityType =
Type.GetType(
string.Format(
"{0}{1}",
EntityNamespacePrefix,
args.CollectionName),
true,
true);
var repositoryType =
typeof(Repository<>)
.MakeGenericType(entityType);
var repository =
(Repository) Activator
.CreateInstance( repositoryType );
return repository.GetAllAsync(); // await not required
}
公共异步任务GetAllentiesFrom(CollectionArgs)
{
变量entityType=
Type.GetType(
字符串格式(
"{0}{1}",
EntityNamespacePrefix,
参数集合名称),
是的,
正确的);
var repositoryType=
类型(存储库)
.MakeGenericType(entityType);
var存储库=
(存储库)激活器
.CreateInstance(repositoryType);
return repository.GetAllAsync();//不需要等待
}
完全没有动力 可以通过两个动态调用来实现:
public async Task<IEnumerable<Entity>> GetAllEntitiesFrom(CollectionArgs args)
{
var entityType = Type.GetType(
string.Format("{0}{1}", EntityNamespacePrefix, args.CollectionName), true, true);
var repositoryType = typeof(Repository<>).MakeGenericType(entityType);
var repository = Activator.CreateInstance(repositoryType);
var task = (Task)((dynamic)repository).GetAllAsync();
await task;
var entities = (IEnumerable<Entity>)((dynamic)task).Result;
return entities;
}
公共异步任务GetAllentiesFrom(CollectionArgs)
{
var entityType=Type.GetType(
格式(“{0}{1}”,EntityNamespacePrefix,args.CollectionName),true,true);
var repositoryType=typeof(Repository).MakeGenericType(entityType);
var repository=Activator.CreateInstance(repositoryType);
var task=(任务)((动态)存储库).GetAllAsync();
等待任务;
变量实体=(IEnumerable)((动态)任务).Result;
返回实体;
}
编辑
尽管上述方法可行,但应该有一个更好的总体设计。不幸的是,MS决定将任务用于异步,因为Task
是类,所以我们不能从协方差中获益。然而,我们可以通过一个小的通用扩展来实现这一点,只需花费一点GC垃圾。但在IMO中,它大大简化了此类设计/实现。请查看:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace Tests
{
// General async extensions
public interface IAwaitable<out TResult>
{
IAwaiter<TResult> GetAwaiter();
TResult Result { get; }
}
public interface IAwaiter<out TResult> : ICriticalNotifyCompletion, INotifyCompletion
{
bool IsCompleted { get; }
TResult GetResult();
}
public static class AsyncExtensions
{
public static IAwaitable<TResult> AsAwaitable<TResult>(this Task<TResult> task) { return new TaskAwaitable<TResult>(task); }
class TaskAwaitable<TResult> : IAwaitable<TResult>, IAwaiter<TResult>
{
TaskAwaiter<TResult> taskAwaiter;
public TaskAwaitable(Task<TResult> task) { taskAwaiter = task.GetAwaiter(); }
public IAwaiter<TResult> GetAwaiter() { return this; }
public bool IsCompleted { get { return taskAwaiter.IsCompleted; } }
public TResult Result { get { return taskAwaiter.GetResult(); } }
public TResult GetResult() { return taskAwaiter.GetResult(); }
public void OnCompleted(Action continuation) { taskAwaiter.OnCompleted(continuation); }
public void UnsafeOnCompleted(Action continuation) { taskAwaiter.UnsafeOnCompleted(continuation); }
}
}
// Your entity framework
public abstract class Entity
{
// ...
}
public interface IRepository<out T>
{
IAwaitable<IEnumerable<T>> GetAllAsync();
}
public class Repository<T> : IRepository<T> where T : Entity
{
public IAwaitable<IEnumerable<T>> GetAllAsync() { return GetAllAsyncCore().AsAwaitable(); }
protected async virtual Task<IEnumerable<T>> GetAllAsyncCore()
{
//return await SQLiteDataProvider.Connection.Table<T>().ToListAsync();
// Test
await Task.Delay(1000);
return await Task.FromResult(Enumerable.Empty<T>());
}
}
public static class Repository
{
public static IAwaitable<IEnumerable<Entity>> GetAllEntitiesFrom(string collectionName)
{
var entityType = Type.GetType(typeof(Entity).Namespace + "." + collectionName, true, true);
var repositoryType = typeof(Repository<>).MakeGenericType(entityType);
var repository = (IRepository<Entity>)Activator.CreateInstance(repositoryType);
return repository.GetAllAsync();
}
}
// Test
class EntityA : Entity { }
class EntityB : Entity { }
class Program
{
static void Main(string[] args)
{
var t = Test();
t.Wait();
}
static async Task Test()
{
var a = await Repository.GetAllEntitiesFrom(typeof(EntityA).Name);
var b = await Repository.GetAllEntitiesFrom(typeof(EntityB).Name);
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Runtime.CompilerServices;
使用System.Threading.Tasks;
命名空间测试
{
//通用异步扩展
公共接口IAwaitable
{
IAwaiter();
TResult结果{get;}
}
公共接口:ICriticalNotifyCompletion,INotifyCompletion
{
布尔已完成{get;}
TResult GetResult();
}
公共静态类异步扩展
{
公共静态IAwaitable ASAWITABLE(此任务){返回新任务可等待(任务);}
类任务等待:IAwaitable,IAwaitable
{
任务等待者任务等待者;
public taskAwaiter(Task Task){taskAwaiter=Task.getwaiter();}
public IAwaiter getwaiter(){返回此;}
public bool IsCompleted{get{return taskAwaiter.IsCompleted;}
public TResult Result{get{return taskAwaiter.GetResult();}
public TResult GetResult(){return taskAwaiter.GetResult();}
public void OnCompleted(Action continuation){taskAwaiter.OnCompleted(continuation);}
public void UnsafeOnCompleted(操作继续){taskAwaiter.UnsafeOnCompleted(继续);}
}
}
//您的实体框架
公共抽象类实体
{
// ...
}
公共接口假定
{
IAwaitable GetAllAsync();
}
公共类存储库:IRepository,其中T:Entity
{
公共IAwaitable GetAllAsync(){返回GetAllAsyncCore().AsAwaitable();}
受保护的异步虚拟任务GetAllAsyncCore()
{
//return wait-SQLiteDataProvider.Connection.Table().toListSync();
//试验
等待任务。延迟(1000);
返回wait Task.FromResult(Enumerable.Empty());
}
}
公共静态类存储库
{
公共静态IAwaitable GetAllentiesFrom(字符串集合名称)
{
var entityType=Type.GetType(typeof(Entity.Namespace+“+collectionName,true,true);
var repositoryType=typeof(Repository).MakeGenericType(entityType);
var repository=(IRepository)Activator.CreateInstance(repositoryType);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace Tests
{
// General async extensions
public interface IAwaitable<out TResult>
{
IAwaiter<TResult> GetAwaiter();
TResult Result { get; }
}
public interface IAwaiter<out TResult> : ICriticalNotifyCompletion, INotifyCompletion
{
bool IsCompleted { get; }
TResult GetResult();
}
public static class AsyncExtensions
{
public static IAwaitable<TResult> AsAwaitable<TResult>(this Task<TResult> task) { return new TaskAwaitable<TResult>(task); }
class TaskAwaitable<TResult> : IAwaitable<TResult>, IAwaiter<TResult>
{
TaskAwaiter<TResult> taskAwaiter;
public TaskAwaitable(Task<TResult> task) { taskAwaiter = task.GetAwaiter(); }
public IAwaiter<TResult> GetAwaiter() { return this; }
public bool IsCompleted { get { return taskAwaiter.IsCompleted; } }
public TResult Result { get { return taskAwaiter.GetResult(); } }
public TResult GetResult() { return taskAwaiter.GetResult(); }
public void OnCompleted(Action continuation) { taskAwaiter.OnCompleted(continuation); }
public void UnsafeOnCompleted(Action continuation) { taskAwaiter.UnsafeOnCompleted(continuation); }
}
}
// Your entity framework
public abstract class Entity
{
// ...
}
public interface IRepository<out T>
{
IAwaitable<IEnumerable<T>> GetAllAsync();
}
public class Repository<T> : IRepository<T> where T : Entity
{
public IAwaitable<IEnumerable<T>> GetAllAsync() { return GetAllAsyncCore().AsAwaitable(); }
protected async virtual Task<IEnumerable<T>> GetAllAsyncCore()
{
//return await SQLiteDataProvider.Connection.Table<T>().ToListAsync();
// Test
await Task.Delay(1000);
return await Task.FromResult(Enumerable.Empty<T>());
}
}
public static class Repository
{
public static IAwaitable<IEnumerable<Entity>> GetAllEntitiesFrom(string collectionName)
{
var entityType = Type.GetType(typeof(Entity).Namespace + "." + collectionName, true, true);
var repositoryType = typeof(Repository<>).MakeGenericType(entityType);
var repository = (IRepository<Entity>)Activator.CreateInstance(repositoryType);
return repository.GetAllAsync();
}
}
// Test
class EntityA : Entity { }
class EntityB : Entity { }
class Program
{
static void Main(string[] args)
{
var t = Test();
t.Wait();
}
static async Task Test()
{
var a = await Repository.GetAllEntitiesFrom(typeof(EntityA).Name);
var b = await Repository.GetAllEntitiesFrom(typeof(EntityB).Name);
}
}
}