为什么我不能实例化一个从匿名对象推断类型的泛型类?
本文关键字:对象 类型 泛型类 实例化 不能 一个 为什么 | 更新日期: 2023-09-27 17:51:22
假设我有一些类——假设的例子:
public class InvalidResponseException<TReq, TResp> : Exception
{
public TReq RequestData { get; protected set; }
public TResp ResponseData { get; protected set; }
public InvalidResponseException(string message, TReq requestData, TResp responseData)
: this(message, null, requestData, responseData)
{
}
public InvalidResponseException(string message, Exception innerException, TReq requestData, TResp responseData)
: base(message, innerException)
{
RequestData = requestData;
ResponseData = responseData;
}
}
class defined…并编译,没有问题。
那么,假设在我的代码体的其他地方,我想抛出这个异常,并为一个或多个类型传递一个匿名对象到异常中。这应该使它具有足够的通用性,以便我可以在任何地方使用它,当我从代码库中的某些调用获得意外响应时:
var reqData = new {
Context = SomeDataContext,
Username = SomeUserName,
ParentID = 54,
RequestValues = ListOfItemsToGet
}
var respData = results.ToList();
string exceptionMessage = string.Format("Invalid response data detected. Requested {0} items received {1}.", ListOfItemsToGet.Count(), results.Count());
throw new InvalidResponseException(exceptionMessage, reqData, respData);
对于大多数匿名调用,您可以使用类型推断,因此您不必在方法调用中定义类型…但是这段代码无法编译。
如果我把鼠标放在reqData的"var"上,编译器告诉我有一个为它定义的类型,尽管一个奇怪的名字没有人可以手动分配…所以理论上我认为这种类型可以由此推断出来。
我最初的结论是,你不能将匿名类型传递给泛型,但你确实可以以某种方式将匿名对象传递给泛型:
var BritishExpats = from p in People
where p.CountryOfBirth == "United Kingdom" && p.CountryOfResidents != p.CountryOfBirth
select new { FirstName = p.FirstName, LastName = p.LastName }
这里的"英国人"是可枚举的
…我可以迭代结果IEnumerable匿名对象和引用他们的公共属性没有任何问题…
foreach (var ExPat in BritishExpats)
{
Console.WriteLine("{0}, {1}", Expat.LastName, Expat.FirstName);
}
当然,我必须在我的循环中使用'var',因为我们不真的知道"英国侨民"是什么类型。
因此,我可以使用匿名对象推断的类型实例化某些类型的类,但不能实例化其他类型的类…
…匿名对象可以实例化什么,不能实例化什么,可以推断出什么,不能推断出什么,有什么规律或道理吗?
不能将泛型、匿名类型和类型推断放在构造函数中。编译器不会得到它。您可以通过诸如
这样的helper类来创建一个变通方法:public static class InvalidResponseExceptionHelper
{
public static InvalidResponseException<TReq, TResp> Create<TReq, TResp>
(string message, TReq requestData, TResp responseData)
{
return new InvalidResponseException<TReq, TResp>(message,
requestData, responseData);
}
}
同样,我没有提到它,但是您的InvalidResponseException
类将无法编译,除非进行大量修改。然而,你的问题的概念通过了。
你的例子不正确。您不需要为构造函数指定泛型类型。
下面一行无效,不能编译
public InvalidResponseException<TReq, TResp>(string message) // TReq,TResp are already known to constructor
我认为你需要类似下面的东西
public class InvalidResponseException<TReq, TResp> : Exception
{
public TReq RequestData { get; protected set; }
public TResp ResponseData { get; protected set; }
public InvalidResponseException (string message):
this(message, default(TReq), default(TResp))
{
}
public InvalidResponseException (string message, TReq requestData, TResp responseData) : base(message)
{
RequestData = requestData;
ResponseData = responseData;
}
}
然后在下面尝试(使用类型推断)
throw new InvalidResponseException(exceptionMessage, "Exception Request", "Exception Response");