字段的原型包含?

发布于 2024-08-05 22:03:49 字数 794 浏览 7 评论 0原文

我有一个简单的对象

[ProtoContract]
public class DataChangedEventArgs<T> : EventArgs
{
    private readonly object key;
    private readonly T data;
    private readonly DataChangeType changeType;

    ///<summary>
    /// Key to identify the data item
    ///</summary>
    public object Key
    {
        get { return key; }
    }

    [ProtoMember(2, IsRequired = true)]
    public T Data
    {
        get { return data; }
    }

    [ProtoMember(3, IsRequired = true)]
    public DataChangeType ChangeType
    {
        get { return changeType; }
    }

,但密钥有问题。它的类型是object,但可以是int、long或string。 我会直观地使用 ProtoIninclude 属性来表示“期望这些类型”,但不幸的是它们只是类属性。 有人知道我该如何解决这个问题吗? 作为背景,公共对象 Key 在这里是出于历史原因(并且遍布各处),所以我非常希望避免所有重构之母;-) 我是否有机会将其序列化,甚至强制将其序列化为字符串?

I have a simple object

[ProtoContract]
public class DataChangedEventArgs<T> : EventArgs
{
    private readonly object key;
    private readonly T data;
    private readonly DataChangeType changeType;

    ///<summary>
    /// Key to identify the data item
    ///</summary>
    public object Key
    {
        get { return key; }
    }

    [ProtoMember(2, IsRequired = true)]
    public T Data
    {
        get { return data; }
    }

    [ProtoMember(3, IsRequired = true)]
    public DataChangeType ChangeType
    {
        get { return changeType; }
    }

and I have a problem with the key. Its type is object, but it can be either int, long or string.
I would intuitively use a ProtoInclude attribute to say "expect these types" but unfortunately they are class only attribute.
Does anybody has any idea how I could work around this ?
For background, the public object Key is here for historical reasons (and all over the place) so I would very much like to avoid the mother of all refactorings ;-)
Any chance I could get this to Serialize, even force it to Serialize as a string ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只是在用心讲痛 2024-08-12 22:03:49

确实有一些技巧可能有效;您提到的 string 非常简单(通过使用标有 [ProtoMember] 的私有属性),但我不确定您如何知道要转换它的类型回到.

然而,有一种基于继承([ProtoInclude])的方法来处理有限数量的类型(提前已知)。这是一个相关示例< /a>,但我会看到我可以使其更具体地针对这种情况...


对于基于字符串的方法,您可以使用前缀吗?即类似:

public object Key {get;set;}

[ProtoMember(1)]
private object KeyString {
    get {
        if(Key == null) return null;
        if(Key is string) return "s:"+(string)Key;
        if(Key is int) return "i:"+Key.ToString();
        // etc
    }
    set {
        if(value == null) { Key = null; }
        else if(value.StartsWith("s:")) {...}
        // etc
    }
}

好的;这是一个例子;我强调,使用固定键会更好;下面的代码有点难看,但是大部分代码都可以隐藏起来并重新使用,所以也许还不错。不过,我更喜欢强类型的键。我可能已经提到过;-p

using System;
using ProtoBuf;
static class Program
{
    static void Main()
    {
        var message1 = new SomeMessageWithVariableKey<string>(123456, "abcdef");
        var clone1 = Serializer.DeepClone(message1);
        Console.WriteLine(clone1.Key);
        Console.WriteLine(clone1.SomeOtherValue);

        var message2 = new SomeMessageWithVariableKey<int>("abcdef", 123456);
        var clone2 = Serializer.DeepClone(message2);
        Console.WriteLine(clone2.Key);
        Console.WriteLine(clone2.SomeOtherValue);
    }
}

[ProtoContract]
[ProtoInclude(1, typeof(ProtoKey<int>))]
[ProtoInclude(2, typeof(ProtoKey<string>))]
abstract class ProtoKey
{
    public static ProtoKey Create(object key)
    {
        if (key == null) return null;
        if (key is string) return new ProtoKey<string> { Value = key };
        if (key is int) return new ProtoKey<int> { Value = key };
        throw new ArgumentException("Unexpected key type: " + key.GetType().Name);
    }

    public abstract object Value { get; protected set;}
    public override string ToString()
    {
        return Convert.ToString(Value);
    }
    public override bool Equals(object obj)
    {
        ProtoKey other = obj as ProtoKey;
        if (other == null) return false;
        return object.Equals(Value, other.Value);
    }
    public override int GetHashCode()
    {
        object val = Value;
        return val == null ? 0 : val.GetHashCode();
    }
}
[ProtoContract]
sealed class ProtoKey<T> : ProtoKey
{
    [ProtoMember(1)]
    public T TypedValue { get; set; }
    public override object Value
    {
        get { return TypedValue; }
        protected set { TypedValue = (T)value; }
    }
}

[ProtoContract]
public class SomeMessageWithVariableKey<T>
{
    private SomeMessageWithVariableKey() { }
    public SomeMessageWithVariableKey(object key, T someOtherValue) {
        Key = key;
        SomeOtherValue = someOtherValue;
    }
    public object Key { get; private set; }

    [ProtoMember(1)]
    private ProtoKey SerializationKey
    {
        get { return ProtoKey.Create(Key); }
        set { Key = value == null ? null : value.Value; }
    }
    [ProtoMember(2)]
    public T SomeOtherValue { get; set; }
}

There are indeed a few tricks that might work; the string one you mention is pretty simple (by using a private property marked with [ProtoMember]), but I'm not sure how you would know what type to convert it back to.

There is, however, an inheritance-based ([ProtoInclude]) way to handle a finite number of types (known in advance). Here's a related example, but I'll see I can make it more specific to this case...


With regard to string-based approaches, you could use a prefix? i.e. something like:

public object Key {get;set;}

[ProtoMember(1)]
private object KeyString {
    get {
        if(Key == null) return null;
        if(Key is string) return "s:"+(string)Key;
        if(Key is int) return "i:"+Key.ToString();
        // etc
    }
    set {
        if(value == null) { Key = null; }
        else if(value.StartsWith("s:")) {...}
        // etc
    }
}

OK; here's an example; I stress that it would be much better to work with fixed keys; the following is a bit ugly, but most of the code can be hidden away and re-used, so maybe not too bad. I'd prefer more strongly-typed keys, though. I might have mentioned that ;-p

using System;
using ProtoBuf;
static class Program
{
    static void Main()
    {
        var message1 = new SomeMessageWithVariableKey<string>(123456, "abcdef");
        var clone1 = Serializer.DeepClone(message1);
        Console.WriteLine(clone1.Key);
        Console.WriteLine(clone1.SomeOtherValue);

        var message2 = new SomeMessageWithVariableKey<int>("abcdef", 123456);
        var clone2 = Serializer.DeepClone(message2);
        Console.WriteLine(clone2.Key);
        Console.WriteLine(clone2.SomeOtherValue);
    }
}

[ProtoContract]
[ProtoInclude(1, typeof(ProtoKey<int>))]
[ProtoInclude(2, typeof(ProtoKey<string>))]
abstract class ProtoKey
{
    public static ProtoKey Create(object key)
    {
        if (key == null) return null;
        if (key is string) return new ProtoKey<string> { Value = key };
        if (key is int) return new ProtoKey<int> { Value = key };
        throw new ArgumentException("Unexpected key type: " + key.GetType().Name);
    }

    public abstract object Value { get; protected set;}
    public override string ToString()
    {
        return Convert.ToString(Value);
    }
    public override bool Equals(object obj)
    {
        ProtoKey other = obj as ProtoKey;
        if (other == null) return false;
        return object.Equals(Value, other.Value);
    }
    public override int GetHashCode()
    {
        object val = Value;
        return val == null ? 0 : val.GetHashCode();
    }
}
[ProtoContract]
sealed class ProtoKey<T> : ProtoKey
{
    [ProtoMember(1)]
    public T TypedValue { get; set; }
    public override object Value
    {
        get { return TypedValue; }
        protected set { TypedValue = (T)value; }
    }
}

[ProtoContract]
public class SomeMessageWithVariableKey<T>
{
    private SomeMessageWithVariableKey() { }
    public SomeMessageWithVariableKey(object key, T someOtherValue) {
        Key = key;
        SomeOtherValue = someOtherValue;
    }
    public object Key { get; private set; }

    [ProtoMember(1)]
    private ProtoKey SerializationKey
    {
        get { return ProtoKey.Create(Key); }
        set { Key = value == null ? null : value.Value; }
    }
    [ProtoMember(2)]
    public T SomeOtherValue { get; set; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文