.net – 如何在没有大型选择/切换的情况下返回特定类类型

我正在构建一系列类,以尝试从主线代码中减少特定类类型的手动编码.

无论我看哪种方式总是需要手动编写特定类类型.

我希望我可以使用反射/激活器等能够使用构造函数中完成的工作来返回classtypes(正确类型)而不需要做大(虽然这里的示例已经减少)选择/切换GetPacket中的语句.

我知道这是VB.Net,但该项目已经用该语言编写,我不介意如果你发布C#示例我只会转换它们.
但请不要将其作为VB.Net问题重新定位,因为它不是关于如何在框架内完成它的语言.

Imports ProtoBuf

Public Class CompatiblePackets
    Inherits Dictionary(Of Packet.PacketType, Base)

    Public Sub New()
        Dim theAssembly As Assembly = Assembly.GetExecutingAssembly
        For Each t As Type In theAssembly.GetTypes
            If t.BaseType Is GetType(Base) Then
                Dim p As Base = CType(t.Assembly.CreateInstance(t.FullName), Base)
                Me.Add(p.PacketTypeIndicator, p)
            End If
        Next
    End Sub

    Public Function GetPacket(id As PacketType, data As Stream) As Base
        Dim activePacket As Base
        If Me.ContainsKey(id) Then
            activePacket = Me(id)
        Else
            activePacket = Me(PacketType.Generic)
        End If
        Try
            Select Case id
                Case PacketType.AcknowledgeBulk
                    Return GetPacket(Of AcknowledgeBulk)(activePacket, data)
                Case PacketType.Generic
                    Return GetPacket(Of Generic)(activePacket, data)
                Case PacketType.Identification
                    Return GetPacket(Of Identification)(activePacket, data)

    '''There are so far about 20 more packet types in the real code.

                Case Else
                    'unknown type "Computer says No!"
            End Select
        Catch ex As Exception
            If data.GetType Is GetType(MemoryStream) Then
                Debug.Print(Core.Text.OutputData(CType(data, MemoryStream).ToArray))
            End If
            Throw
        End Try
        Debug.Print("Wtf - " & id.ToString())

        Return New NoOperation
    End Function

    Private Function GetPacket(Of t)(activePacket As Packet.Base, data As Stream) As t
        Return Serializer.Deserialize(Of t)(data)
    End Function
End Class

最佳答案 如果我正确理解了这个问题,看起来你应该使用Serializer.NonGeneric;这有多种方法可以手动传递Type而不使用泛型,包括Serialize和Deserialize.

请注意,对于此方案,Serializer.NonGeneric还具有用于异构标头标记消息的特定API,您可能会发现这对于网络流方案很有用:

static void Main() {
    // memory-stream only for example - would work fine with NetworkStream too
    using(var ms = new MemoryStream()) {
        // this is just to simulate an incoming network-stream
        Serializer.SerializeWithLengthPrefix(ms, new Foo { Name = "abc" },
           PrefixStyle.Base128, 1); // tag 1 for Foo
        Serializer.SerializeWithLengthPrefix(ms, new Bar { Value = 123 },
           PrefixStyle.Base128, 2); // tag 2 for Bar
        ms.Position = 0;

        // now we'll consume it

        //first setup some map of 1=Foo, 2=Bar - any mechanism will suffice
        var typeMap = new Dictionary<int, Type>{
            {1, typeof(Foo)},
            {2, typeof(Bar)}
        };
        Serializer.TypeResolver resolver = i => {
            Type type;
            return typeMap.TryGetValue(i, out type) ? type : null;
        };
        object obj;
        while(Serializer.NonGeneric.TryDeserializeWithLengthPrefix(
            ms, PrefixStyle.Base128,resolver,out obj))
        {
            Console.WriteLine(obj);
        }
        Console.WriteLine("<EOF>");

    }
}
[ProtoContract]
class Foo {
    [ProtoMember(7)]
    public string Name{ get; set; }

    public override string ToString() { return "Foo: " + Name; }
}
[ProtoContract]
class Bar {
    [ProtoMember(4)]
    public int Value { get; set; }

    public override string ToString() { return "Bar: " + Value; }
}

这输出:

Foo: abc
Bar: 123
<EOF>

在v2中,请注意TypeModel将非泛型API公开为主要接口(Serializer API仅用作默认模型的代理).

点赞