C# 我可以拥有/使用带有列表的字段/属性吗<;类<;T>&燃气轮机;哪里可以有什么? 原始问题
我试图为我的web请求创建一个通用类C# 我可以拥有/使用带有列表的字段/属性吗<;类<;T>&燃气轮机;哪里可以有什么? 原始问题,c#,generics,types,.net-4.5,covariance,C#,Generics,Types,.net 4.5,Covariance,我试图为我的web请求创建一个通用类 internal class Request<TRequest, TResponse> where TRequest : class where TResponse : class { public Uri RequestUri; public TRequest RequestItem; public TResponse ResponseItem; ... } 但是,我无法在请求列表中添加任何内容
internal class Request<TRequest, TResponse>
where TRequest : class
where TResponse : class
{
public Uri RequestUri;
public TRequest RequestItem;
public TResponse ResponseItem;
...
}
但是,我无法在请求列表中添加任何内容,因为当我尝试时:
var a = new Request<FooRequest, BarResponse>();
requests.Add(a);
这只是一个列表
,不幸的是,我不能在类中,在方法之外声明任何类型为var
的东西
列表
或列表
同样,不是列表的示例。但是让我们试试列表
。。。失败:
无法从My.Services.Request
转换为My.Services.Request
列表
->现在,布莱恩·瓦茨(Bryan Watts),在所有答案中得票最少,找到了一种有趣的方法来检索TRequest
和TreResponse
。他在接口/基类中声明:
Type DataType { get; }
object Data { get; }
这就解决了“如何检索变体”的问题类型RequestType
和类型ResponseType
。这意味着
部件将无用。这意味着我将只使用列表
,而我的Stackoverflow问题的答案是:不,你不能使用/受益于在C#中存储列表
第二次编辑
显然,我没能实现布莱恩·瓦茨的解决方案。所以我不能写反序列化(请求)
。所以我陷入了困境:如果我将请求添加到请求列表中,我就有了运行时类型,我不能再使用泛型方法了。我不知道通用方法这么不方便。
:(
第二个结论
我将有一个列表
,每个请求
都将为请求类型保留一个枚举
,然后我将打开此枚举并手动记录所有可能的请求调用:
switch (@req.RequestType)
{
case RequestType.FirstKindOfRequest:
await Deserialize<FirstKindOfRequest, FirstKindOfResponse>(req);
break;
case RequestType.SecondKindOfRequest:
...
}
开关(@req.RequestType)
{
案例RequestType.FirstKindOfRequest:
等待反序列化(req);
打破
案例请求类型。第二类请求:
...
}
不幸的是,这是我唯一能找到的保存Class
列表的方法,其中T
应该是任何东西。我认为泛型通配符可以帮助您:
由于这至少在不久的将来不会发生,我认为有三种选择:
- 你可以投票,等待,并希望微软在泛型中采用通配符
- 正如Mrida所评论的,您可以将代码转换为使用接口,然后使用C#协方差
- 如果协方差不是一个可接受的解决方案,您可以定义一个只有非泛型功能的非泛型基类
RequestBase
,并列出RequestBase
(edit:我想这是HenkHolterman的评论)。或者,如果您不想更改请求
类,可以使用非通用功能定义非通用包装
我认为泛型通配符可以帮助您:
由于这至少在不久的将来不会发生,我认为有三种选择:
- 你可以投票,等待,并希望微软在泛型中采用通配符
- 正如Mrida所评论的,您可以将代码转换为使用接口,然后使用C#协方差
- 如果协方差不是一个可接受的解决方案,您可以定义一个只有非泛型功能的非泛型基类
RequestBase
,并列出RequestBase
(edit:我想这是HenkHolterman的评论)。或者,如果您不想更改请求
类,可以使用非通用功能定义非通用包装
通过提取变体IRequest
接口,您可以利用接口差异:
interface IRequest<out T, out T1>
{
}
如果您想要一些特定于类型的行为,您仍然必须将列表的内容强制转换为更特定的类。在高流量情况下,这可能会影响性能,也可能不会影响性能
另一个选项是存储请求的字符串内容,或将其提取到抽象基类。此抽象类的列表足以用于缓存和日志记录。您可以有如下内容:
abstract class BaseRequest
{
public string RequestContent { get; protected set; }
public string ResponseContent { get; set; }
}
class Request<TRequest, TResponse> : BaseRequest
where TRequest : class
where TResponse : class
抽象类BaseRequest
{
公共字符串RequestContent{get;protected set;}
公共字符串响应内容{get;set;}
}
类请求:BaseRequest
特雷奎斯特:课堂在哪里
在哪里响应:类
你仍然可以写:
var s = new List<BaseRequest>();
s.Add(new Request<c1, c2>());
var s=newlist();
s、 添加(新请求());
通过提取变体IRequest
接口,您可以利用接口差异:
interface IRequest<out T, out T1>
{
}
如果您想要一些特定于类型的行为,您仍然必须将列表的内容强制转换为更特定的类。在高流量情况下,这可能会影响性能,也可能不会影响性能
另一个选项是存储请求的字符串内容,或将其提取到抽象基类。此抽象类的列表足以用于缓存和日志记录。您可以有如下内容:
abstract class BaseRequest
{
public string RequestContent { get; protected set; }
public string ResponseContent { get; set; }
}
class Request<TRequest, TResponse> : BaseRequest
where TRequest : class
where TResponse : class
抽象类BaseRequest
{
公共字符串RequestContent{get;protected set;}
公共字符串响应内容{get;set;}
}
类请求:BaseRequest
特雷奎斯特:课堂在哪里
在哪里响应:类
你仍然可以写:
var s = new List<BaseRequest>();
s.Add(new Request<c1, c2>());
var s=newlist();
s、 添加(新请求());
这是一个典型的情况。以前也问过很多次。我看到两种方法
->显而易见的选择是使用非泛型基类/接口,该基类/接口可以解释所有请求类型,然后继续使用列表
->第二种方法是利用
var s = new List<BaseRequest>();
s.Add(new Request<c1, c2>());
interface IMessage //I will call it IMessage for now
{
//implement whatever that make deserializing possible
}
class FooRequest : IMessage
{
}
class BarResponse : IMessage
{
}
interface IRequest<out TRequest, out TResponse>
where TRequest : IMessage
where TResponse : IMessage
{
TRequest RequestItem { get; }
TResponse ResponseItem { get; }
//whatever fits, but only getters for out parameter types
}
class Request<TRequest, TResponse> : IRequest<TRequest, TResponse>
where TRequest : IMessage
where TResponse : IMessage
{
//you can extend interface properties with setters here
}
var requests = new List<IRequest<IMessage, IMessage>>();
var a = new Request<FooRequest, BarResponse>();
requests.Add(a);
foreach (var request in requests)
{
Deserialize(request);
}
void Deserialize<TRequest, TResponse>(IRequest<TRequest, TResponse> request)
where TRequest : IMessage
where TResponse : IMessage
{
//have access to request.RequestItem, request.ResponseItem etc
}