【发布时间】:2015-08-19 23:38:42
【问题描述】:
我正在尝试使用dynamic 来解决由于设计或缺乏设计造成的不便(如果有兴趣Simplify method retrieving data from generic repository,可以在这里找到“不便”)。
简而言之,我需要返回 Entity 实例的集合。类很简单:
[JsonObject]
public class Entity
{
[PrimaryKey]
[JsonProperty(PropertyName = "id")]
public virtual int Id { get; set; }
[JsonIgnore]
public string Content { get; set; }
}
所以Entity 只有Id 和Content。继承类可能有其他属性,但我只对 Content 部分(复杂 JSON)感兴趣。
可以通过通用Repository<T> 访问各种不同的实体。我需要知道具体类的Type,因为T 通过构建在 SQLite-net ORM 之上的数据提供程序映射到底层 SQLite 表。
例如,如果我有Schedule : Entity,那么我将使用Repository<Schedule> 来操作名为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.
}
主要问题是“命令”来自 JavaScript 客户端,因此我将接收 JSON 格式的请求。在这个 JSON 中,我有一个名为 CollectionName 的属性,它指定了所需的表(和具体类型)。
我需要/想要的是一段漂亮干净的代码,它可以从任何给定的表中获取实体。所以,下面的方法应该可以解决我所有的问题,但事实证明它并没有......
public async Task<IEnumerable<Entity>> GetAllEntitiesFrom(CollectionArgs args)
{
// args.CollectionName is type of entity as string
// namespace + collection name is mapped as correct type
// e.g. MyNamespace.Schedule
Type entityType = Type.GetType(
string.Format("{0}{1}", EntityNamespacePrefix, args.CollectionName), true, true);
// get correct repository type using resolved entity type
// e.g. Repository<MyNamespace.Schedule>
Type repositoryType = typeof(Repository<>).MakeGenericType(entityType);
dynamic repository = Activator.CreateInstance(repositoryType);
// Below `GetAllAsync()` returns `Task<IEnumerable<T>>`.
// this blocking call works 100%
//var entities = repository.GetAllAsync().Result;
// this non-blocking call works when it feels like it
var entities = await repository.GetAllAsync();
return entities;
}
因此,如果(上图)我使用阻塞 .Result 一切正常,就像一个魅力。相反,如果我使用await,代码可能会或可能不会工作。这似乎真的取决于行星的位置和/或飞行意大利面怪物的情绪波动。
随机,但通常情况下,给定的线会抛出
无法转换类型的对象 'System.Runtime.CompilerServices.TaskAwaiter'1[System.Collections.Generic.IEnumerable'1[MyNamespace.Schedule]]' 输入“System.Runtime.CompilerServices.INotifyCompletion”。
我正在使用 .NET 4.0 扩展框架。
【问题讨论】:
-
那里没有得到很好的回答 - 但仍然 - 如果您的 Repository
类型派生自可以返回延迟(抽象)GetAllAsync 的非泛型,您似乎可以避免动态存储库 实现。然后,您将有一个具体的点来调用,而不是动态存储库。 -
可能你不应该首先在这里等待动态表达式。
await (Task<IEnumerable<T>>)repository.GetAllAsync()有什么问题?这更好,因为它使用的动态更少。 -
没有
T,只有Type在运行时解析。我真的不知道如何从typeof(Schedule)创建等效的(Task<IEnumerable<Schedule>>)。而且T也不能是普通的Entity(抛出异常)。 -
好的,使用
await (Task)...。然后您可以使用dynamic从该任务中提取结果。动态越少越好。
标签: c# .net async-await