为什么我不能实例化一个从匿名对象推断类型的泛型类?

时间:2013-01-11 04:26:28

标签: c# instantiation type-inference anonymous-objects

假设我有一些类 - 假设的例子:

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;
    }
}

好的,班级定义了...并编译,没问题。

所以,让我说在我的代码体中的其他地方,我想抛出这个异常并将一个匿名对象传递给我的异常中的一个或多个类型。这应该保持足够的通用性,以便我可以在我的代码库中从某些调用获得意外响应的任何地方使用它:

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 }

这里“BritishPeople”是IEnumerable&lt; T&gt;其中T被推断为'a

...我可以迭代生成的IEnumerable匿名对象并引用它们的公共属性而不会出现任何问题......

foreach (var ExPat in BritishExpats)
{
    Console.WriteLine("{0}, {1}", Expat.LastName, Expat.FirstName);
}

当然我必须在循环中使用'var',因为我们

所以我可以使用匿名对象推断的类型来实例化某些类型的类,而不是其他类... ...

...有什么可以和不可以被匿名对象实例化,推断和推断出来的押韵或理由?

2 个答案:

答案 0 :(得分:2)

您不能将构造函数中的泛型,匿名类型和类型推断放在一起。编译器就是不会得到它。您可以通过辅助类创建变通方法,例如:

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类将无法编译。然而,你的问题的概念已经过去了。

答案 1 :(得分:0)

您的示例不正确。您不需要为构造函数指定泛型类型。他们已经知道了。

以下行无效,不会编译

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");