6

Quick question, is it possible to enable to EnumPassthru by default on all enum types? At the moment I have to enable this on each enum type manually or use the following method to apply it automatically to my DTO assembly types:

    public static void ConfigureEnumTypes(RuntimeTypeModel tm, Assembly a)
    {
        foreach (var type in a.GetTypes())
        {
            if (type.IsEnum && type.GetCustomAttribute<ProtoContractAttribute>() != null)
                tm[type].EnumPassthru = true;
        }
    }

If there is a better way, I'd like to know. Thanks.

Barguast
  • 5,926
  • 9
  • 43
  • 73
  • Your example enables it only for those enums marked with the attribute - cant that same attribute also declare it as enum-passthru? – Marc Gravell Jun 21 '13 at 22:48
  • As an option of the ProtoContract attribute? I don't think I can enable enum passthru with that, can I? If so then that'd be ideal, but I don't see the parameter for it. – Barguast Jun 21 '13 at 23:21
  • I may have misremembered. I'll look over the weekend. – Marc Gravell Jun 22 '13 at 06:28
  • Sorry to nag, but did you happen to find anything? Thanks again. – Barguast Jun 24 '13 at 11:34
  • I got drowned in some unrelated work that needed finishing for Monday; will look in the morning – Marc Gravell Jun 24 '13 at 20:05
  • [*poke*] :) I'm fairly sure there isn't an option for this at the moment, but hopefully I'm wrong. Hopefully there will be at some point. In the meantime, is there a way I can automate the setting of this property for all of my DTO classes without having to scan through individual assemblies? – Barguast Jun 26 '13 at 22:53
  • well, one hacky way of doing it is to add `[Flags]` to those enums... probably not a good thing to do in most cases, though. Looking now. – Marc Gravell Jun 27 '13 at 06:39
  • @MarcGravell Any updates on being able to disable the enum validation by default for the entire application? The hackery to set EnumPassthru makes me a little sad. – roken Sep 07 '13 at 18:22

1 Answers1

5

This passes in the next build:

[TestFixture]
public class SO17245073
{
    [Test]
    public void Exec()
    {
        var model = TypeModel.Create();
        Assert.IsFalse(model[typeof(A)].EnumPassthru, "A");
        Assert.IsTrue(model[typeof(B)].EnumPassthru, "B");

        Assert.IsFalse(model[typeof(C)].EnumPassthru, "C");
        Assert.IsTrue(model[typeof(D)].EnumPassthru, "D");

        Assert.IsTrue(model[typeof(E)].EnumPassthru, "E");
        Assert.IsTrue(model[typeof(F)].EnumPassthru, "F");

        Assert.IsFalse(model[typeof(G)].EnumPassthru, "G");
        Assert.IsFalse(model[typeof(H)].EnumPassthru, "H");            
    }

    // no ProtoContract; with [Flags] is pass-thru, else not
    public enum A { X, Y, Z }
    [Flags]
    public enum B { X, Y, Z }

    // basic ProtoContract; with [Flags] is pass-thru, else not
    [ProtoContract]
    public enum C { X, Y, Z }
    [ProtoContract, Flags]
    public enum D { X, Y, Z }

    // ProtoContract with explicit pass-thru enabled; always pass-thru
    [ProtoContract(EnumPassthru = true)]
    public enum E { X, Y, Z }
    [ProtoContract(EnumPassthru = true), Flags]
    public enum F { X, Y, Z }

    // ProtoContract with explicit pass-thru disabled; never pass-thru
    // (even if [Flags])
    [ProtoContract(EnumPassthru = false)]
    public enum G { X, Y, Z }
    [ProtoContract(EnumPassthru = false), Flags]
    public enum H { X, Y, Z }
}

From your example code here:

if (type.IsEnum && type.GetCustomAttribute<ProtoContractAttribute>() != null)

it sounds like all you should need to do, since you already have [ProtoContract], is to make that [ProtoContract(EnumPassthru = true)] on your enum declarations.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @Barguast I haven't switched to my build VM to do a formal build - let me know if you want me to send you a "built on my dev PC" pre-release build – Marc Gravell Jun 27 '13 at 09:24
  • I think I'm happy to wait for the next release. Thanks again for the help and adding this feature. – Barguast Jun 27 '13 at 22:49
  • Hey Marc, thanks for working on this! I also have a couple of quick questions: 1) I assume this is only updated in protobuf-net v2, correct? 2) Can this option be applied to collections? For example, can I get passthru behavior in Dictionary? – Amber Scouras Jul 10 '13 at 18:41
  • 1
    @AmberScouras I don't know if I have an explicit test for it, but a pass-thru on `MyEnum` should apply automatically to the `MyEnum` in `Dictionary` – Marc Gravell Jul 10 '13 at 19:11
  • @MarcGravell is there any way to do this in the other direction? I'm generating the C# from .proto files using ProtoGen. Is there any way of turning EnumPassthru on from a .proto or VS custom tool option? Otherwise I'd have to post-process the generated C#. (As it stands our system is dependent upon the client applications upgrading to handle the new enum values so ideally I'd like to drive this from the .proto file.) Would it not be better if unrecognised enum values be apped to the default value specified on the message field? – Paul Ruane Jul 11 '13 at 13:57
  • @PaulRuane well, you could make a 2 line tweak to the `csharp.xslt` file; but there isn't anything inbuilt into protogen right now. However, you could have (early in your app startup): `RuntimeTypeModel.Default[typeof(YourEnum)].EnumPassthru = true;` – Marc Gravell Jul 11 '13 at 14:11
  • @MarcGravell, yeah that appears to be my best option right now but I'd have to get the code into each client app which are run by other teams plus it's a bit fragile: if we add additional enum types to our server's proto files then we have to rely upon all those client apps turning on pass thru for the new enums (or use code like in the question above). Defaulting unrecognised values to the field default (where one is available) would be much more preferable. – Paul Ruane Jul 11 '13 at 14:20
  • @MarcGravell, from the Protocol Buffers language guide "...a field with an enum type can only have one of a specified set of constants as its value (if you try to provide a different value, the parser will treat it like an unknown field)." This, to me at least, suggests it shouldn't result in an exception but that it should be ignored (which would suggest to me that the default should be used for the field). – Paul Ruane Jul 11 '13 at 15:06
  • @Paul technically it shouldn't be ignored - it should be stored in extension data if available. I suppose I should look at that, though - sounds like a regression. – Marc Gravell Jul 11 '13 at 16:00