pizheng/protobuf-net

Surrogates do not work with nullable types

Closed this issue · 4 comments

What steps will reproduce the problem?

public class DTO
{
  public DateTimeOffset? Time { get; set; }
}

var model = TypeModel.Create();
model.Add(typeof(DateTimeOffsetSurrogate), false).Add("Content");
model.Add(typeof(DateTimeOffset), 
false).SetSurrogate(typeof(DateTimeOffsetSurrogate));
model.Add(typeof(DTO), false).Add("Time");
model.Compile();

What is the expected output? What do you see instead?

Compilation and serialization with the surrogate works great unless the Time 
property is nullable, as above.  When it is nullable, I get the following 
exception at Compile()-time:

InvalidOperationException : Cannot load the address of a struct at the head of 
the stack
  at ProtoBuf.Compiler.CompilerContext.LoadAddress(Local local, Type type)
  ...

What version of the product are you using? On what operating system?

v2.0.0.431, .NET 4.

Please provide any additional information below.

I tried adding a surrogate for Nullable<DateTimeOffset>, but it didn't seem to 
make any difference.  Auto-compiling at serialization time also made no 
difference.

Original issue reported on code.google.com by ladene...@gmail.com on 15 Aug 2011 at 3:19

Oh, here's the surrogate too, in case it matters:

public class DateTimeOffsetSurrogate
{
  public DateTimeOffsetSurrogate(DateTimeOffset dto)
  {
    Content = dto.ToString("o");
  }

  public string Content { get; set; }

  public static explicit operator DateTimeOffsetSurrogate(DateTimeOffset dto)
  {
    return new DateTimeOffsetSurrogate(dto);
  }

  public static explicit operator DateTimeOffset(DateTimeOffsetSurrogate dtos)
  {
    return DateTimeOffset.Parse(dtos.Content, null, DateTimeStyles.RoundtripKind);
  }
}

Original comment by ladene...@gmail.com on 15 Aug 2011 at 3:20

Hi! I had the same problem and after a while I found a workaround.
I just commented throwing this exception in a source code. See the file 
CompilerContext.cs line 648:
I replaced line
if (local == null) throw new InvalidOperationException("Cannot load the address 
of a struct at the head of the stack");
with 
if (local == null) return;
I ran unittests and all of them passed successfully.
It should be noted that null argument is passed to this method directly in 
FiledDecorator.cs line 55
ctx.ReadNullCheckedTail(field.FieldType, Tail, null);
Generally it works for me.
You can use attached patch.

Original comment by nerzhulart on 24 Nov 2011 at 12:06

Attachments:

Any news on fixing this issue or a work around? Our code makes heavy use of 
Nullable<DateTimeOffset> and we would like to use protobuf for serialization.

Original comment by renemygi...@gmail.com on 9 Jul 2012 at 11:56

r521

Original comment by marc.gravell on 11 Jul 2012 at 6:34

  • Changed state: Fixed