Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Typedef that preserves attributes

The problem: I have Dictionary<String, String> that I need an alias to, but I also need to serialize/deserialize it.

Solutions I've tried:

class Foo : Dictionary<String, String> { }

but that work because I would have to create a Deserialization constructor and that would be a bit silly when Dictionary already can be deserialized.

I also tried

using Foo = System.Collections.Generic.Dictionary<String, String>;

but I need this to work in more that one file and if add that line in all the files that need it, I'll be removing half the point of typedefs (that is, if I need to change the type, I can do so easily)

What can I do about this?

like image 386
Drew Avatar asked Feb 04 '11 05:02

Drew


2 Answers

With the alias approach attributes are preserved, but you state that is too much overhead (per-file etc).

Type-level attributes are genercally preserved - but it depends on the attribute - for [Serializable], note that it has:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct
| AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)]

the Inherited = false being significant - i.e. it is not inherited.

Personally I probably would have focused on getting the serialization ctor/callbacks working in the first example - I doubt it would have needed much more effort. The following seems fine:

[Serializable]
public class Foo: Dictionary<string, string> {
    public Foo() : base() { }
    public Foo(SerializationInfo info, StreamingContext context) : base(info, context) { }
    public Foo(int capacity) : base(capacity) { }
    public Foo(IEqualityComparer<string> comparer): base(comparer) {}
    public Foo(IDictionary<string,string> dictionary) : base(dictionary) { }
    public Foo(int capacity, IEqualityComparer<string> comparer) : base(capacity, comparer) { }
    public Foo(IDictionary<string, string> dictionary, IEqualityComparer<string> comparer) : base(dictionary, comparer) { }
}

However, here's an alternative via encapsulation:

[Serializable]
public class Foo : IDictionary<string,string>
{
    private readonly Dictionary<string, string> inner = new Dictionary<string, string>();

    public void Add(string key, string value)
    {
        inner.Add(key, value);
    }

    public bool ContainsKey(string key)
    {
        return inner.ContainsKey(key);
    }

    public ICollection<string> Keys
    {
        get { return inner.Keys; }
    }

    public bool Remove(string key)
    {
        return inner.Remove(key);
    }

    public bool TryGetValue(string key, out string value)
    {
        return inner.TryGetValue(key, out value);
    }

    public ICollection<string> Values
    {
        get { return inner.Values; }
    }

    public string this[string key]
    {
        get
        {
            return inner[key];
        }
        set
        {
            inner[key] = value;
        }
    }

    void  ICollection<KeyValuePair<string, string>>.Add(KeyValuePair<string, string> item)
    {
        ((IDictionary<string,string>)inner).Add(item);
    }

    public void Clear()
    {
        inner.Clear();
    }

    bool ICollection<KeyValuePair<string, string>>.Contains(KeyValuePair<string, string> item)
    {
        return ((IDictionary<string, string>)inner).Contains(item);
    }

    void  ICollection<KeyValuePair<string, string>>.CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
    {
        ((IDictionary<string, string>)inner).CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return inner.Count; }
    }

    bool  ICollection<KeyValuePair<string, string>>.IsReadOnly
    {
        get { return ((IDictionary<string, string>)inner).IsReadOnly; }
    }

    bool ICollection<KeyValuePair<string, string>>.Remove(KeyValuePair<string, string> item)
    {
        return ((IDictionary<string, string>)inner).Remove(item);
    }

    public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
    {
        return inner.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return inner.GetEnumerator();
    }
}
like image 163
Marc Gravell Avatar answered Oct 25 '22 02:10

Marc Gravell


Mmm "that would be a bit silly when Dictionary already can be deserialized." I wouldn't say it's silly to call a base ctor in (almost) any case + it's 1 min effort, so I'd say do it...

[Serializable]
public class Foo : Dictionary<string, string>
{
    public Foo()
        : base()
    {
    }
    public Foo(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }   

}

or

[Serializable]
public class Foo<TKey,TValue> : Dictionary<TKey,TValue>
{
    public Foo()
        : base()
    {
    }
    public Foo(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }   

}
like image 41
Walt Jimi Avatar answered Oct 25 '22 01:10

Walt Jimi