我不确定我是否可以这样做,但我正在构建一个应用程序的服务层,需要将一种类型的实体添加到另一个实体。一个例子可能是在一个类别中添加一篇文章。它通过服务类完成此操作,例如:
public class ArticleService {
public IResponse AddArticleToCategory(IAddRelatedItemRequest<Category, Article> request) {
// do stuff with the request
}
}
我希望IAddRelatedItemRequest接口是通用的,因此它可以用于任何添加请求,类似于:
public interface IAddRelatedItemRequest<T, U>
where T : class
where U : class {
Object Key { get;set; }
List<Object> RelatedKey { get;set; }
}
发生的是请求需要项目的主键(例如类别)和相关项目的主键列表(例如文章)。然后,具体ArticleService中的AddCommentToArticle类通过其键检索项目,然后将相关的关键项添加到其中。
(NB我不想发生的是提供实际实体和相关实体列表 - 它需要通过原始主键完成)
我想以某种方式强烈输入请求,因此我可以提供(例如)Guid和整数列表而不是提供对象和对象列表。
我并不特别想通过Generics提供这两种类型,因为它使代码不太可读,并且对象的键可能会改变类型。
理想情况下,我想以某种方式提取实体ID的类型并将其包含在界面中。这可能吗?
答案 0 :(得分:1)
我不太确定我是完全关注你的例子,但听起来你想要的是这样的:
interface IKeyResolver<T, TKey>
{
TKey GetKey(T item);
}
public interface IAddRelatedItemRequest<TParentKey, TChildKey>
{
TParentKey Key { get;set; }
List<TChildKey> RelatedKey { get;set; }
}
// assume categories have an int key
class CategoryKeyResolver : IKeyResolver<int>
{
int GetKey(Category c) { return c.CategoryId; }
}
// assume articles use a GUID
class ArticleKeyResolver : IKeyResolver<Guid>
{
Guid GetKey(Article a) { return a.ArticleId;
}
然后,您将在服务方法中使用相应的密钥解析器。密钥解析器可以是您服务中的属性,也可以根据需要实例化相应的密钥解析器。当您的基础持久性机制本身是通用的(例如,通用的Repository实现)时,类似于密钥解析器的东西非常有用。
答案 1 :(得分:0)
C#编译器可以为您推断出类型 - 至少给出一个定义它们的位置。首先,您无法使用where T : class
,因为int
和Guid
不是引用类型。因此,您的界面定义如下所示:
public interface IAddRelatedItemRequest<T, U>
{
T Key { get; set; }
IList<U> RelatedKey { get; set; }
}
然后你会实现它。这将是您键的类型的中心“控制点”:
public class SomeItemRequest : IAddRelatedItemRequest<int, int>
{
}
使您的方法通用,C#编译器可以为您推断类型:
public static IResponse AddArticleToCategory<T, U>(IAddRelatedItemRequest<T, U> request)
{
return null;
}
// Usage:
ArticleService.AddArticleToCategory(new SomeItemRequest());
我相信用法示例就是你所追求的。