C#泛型类型推断与多种类型

4
我有以下通用方法,将一个类型的输入对象序列化为超类型,如下所示:

public string SerialiseAs<TResult, TInput>(TInput input) where TInput : TResult
{
    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TResult));
    MemoryStream stream = new MemoryStream();
    ser.WriteObject(stream, input);
    stream.Position = 0;
    StreamReader reader = new StreamReader(stream);
    return reader.ReadToEnd();
}

我需要调用这个方法并指定两个泛型类型,如下:

MySubType x = new MySubType();
string json = SerialiseAs<MySuperType, MySubType>(x);

我的问题是,为什么在这种情况下无法推断出 TInput?是因为实际上没有使用 TResult 作为返回类型吗?下面的代码更简洁,但由于缺少输入类型而无法编译:
MySubType x = new MySubType();
string json = SerialiseAs<MySuperType>(x);

C++多好啊?如果C#能有(成员)typedef就好了,我很想要那个。但是不行啊,它不是那样工作的。 - sehe
2个回答

8
我的问题是,在这种情况下为什么无法推断TInput?
可以 - 这是TResult无法推断,而且没有办法指定“部分”推断。
有时候你可以将类型参数分离到一个通用类型和一个通用方法中,因此你最终会得到:
// Explicitly state TResult, and infer TInput
Serializer<MySuperType>.Serialize(x);

这样做更有意义。我喜欢在类级别指定输出类型的想法,但输入类型是推断出来的。这样我仍然可以在通用的“序列化”方法上进行继承检查。我也可以尝试使用流畅的语法,比如Serialise(x).As<MySuperType>(),但对于我实际使用的情况来说可能有点复杂。 - Adam Rodger
@AdamRodger:如果你把TResult放在第二个位置,那么会比较棘手,因为你无法强制实施TInput:TResult的约束条件。当然,如果你不介意失去编译时的约束条件,那就不是问题了。 - Jon Skeet
标记为答案的原因是您无法部分指定泛型类型。 - Adam Rodger

7

为什么不这样写:

public string SerialiseAs<TResult>(TResult input)
{
    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TResult));
    MemoryStream stream = new MemoryStream();
    ser.WriteObject(stream, input);
    stream.Position = 0;
    StreamReader reader = new StreamReader(stream);
    return reader.ReadToEnd();
}

TInput继承自TResult,因此您实际上不需要指定任何内容。

这个方法不能与 DataContractJsonSerialiser 一起使用,因此我改变了方法来接受两种类型。当您将实例作为 MySuperClass 传递时,MySubType 中的任何额外属性都会从序列化结果中省略。您的输出中也不会得到 __type 属性,而我需要它。您必须将实例作为子类型传递,但告诉它以超类型进行序列化。 - Adam Rodger
@AdamRodger - 这很奇怪。我不知道 DataContractJsonSerializer 如何确定您传递给它的变量类型。WriteObject() 方法将一个简单的 object 作为其参数。您确定吗? - Vilx-
是的,绝对确定。我还有一个Serialise方法,不像上面那个方法那样进行类型洗牌,但在相同的输入下,它们都会产生不同的输出。__type属性缺失了。 - Adam Rodger
@AdamRodger - 对我来说运行得很好:http://pastebin.com/4gTfrvuy 你可能在使用已知类型或其他什么魔法吗?我对WCF不是很熟悉,但它要求我在类A上放置这个奇怪的KnownType属性才能工作。异常消息中还提到了一个DataContractResolver - Vilx-
是的,MySuperType 是一个抽象类,有许多实现子类(通过 KnownType 指定)。您需要自动添加 __type 属性,以便在客户端进行反序列化。我认为这个细节并不重要,因为我有一个可行的方法,只是想知道为什么我不能推断输入类型。这只是一个小助手方法,用于我的单元测试,所以我可以检查必需的属性是否存在,非必需的默认属性是否被省略等。 - Adam Rodger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接