I have a convenience class which is essentially a dictionary that holds a tag/value pair list for submission to an API.
At its very basic level all I did is this:
enum Tag
{
Name, Date, //There are many more
}
class RequestDictionary : Dictionary<Tag, string>
{
}
This maps well to the needs of the API, since the whole thing gets sent and parsed as a string. However, it's not so great for the caller; for example, the caller has to know how to format the Date
properly.
To address this, I started adding tag-specific properties that are type safe. I have them sequestered in separate interface so they don't get confused with the normal Dictionary properties.
enum Tag
{
Name, Date
}
interface ITags
{
string Name { get; set; }
DateTime Date { get; set; }
}
class RequestDictionary : Dictionary<Tag, string>, ITags
{
public ITags Tags { get { return this; } }
string ITags.Name
{
get { return this[Tag.Name]; }
set { this[Tag.Name] = value; }
}
DateTime ITags.Date
{
get { return DateTime.ParseExact(this[Tag.Date], API_DATE_FORMAT, CultureInfo.InvariantCulture); }
set { this[Tag.Name] = value.ToString(API_DATE_FORMAT); }
}
}
After introducing this interface, the caller has a choice of
dict[Tag.Date] = DateTime.Now.ToString(API_DATE_FORMAT);
or
dict.Tags.Date = DateTime.Now;
The latter is less work for the caller, especially since API_DATE_FORMAT is actually private.
I want the caller to be able to use object initializer syntax:
var dict = new RequestDictionary
{
Tags.Date = DateTime.Now
}
...but this does not compile (the error is "Invalid initializer member declarator").
So it seems that the caller will need to use
var dict = new RequestDictionary
{
{ Tags.Date, DateTime.Now.ToString(API_DATE_FORMAT) }
};
...which is obviously not as well encapsulated or convenient.
Is there any way to initialize an object using object initializer syntax when the property you wish to access is exposed via an interface that is not included in the default class interface?
The following code may serve your needs:
var dict = new RequestDictionary
{
Tags = { Date = DateTime.Now }
};
The key is to use Tags = { Date
(i.e. go one level down at a time) rather than Tags.Date =
.
I acknowledge that the code looks like it won't work, since it looks like you are assigning to a read-only property (i.e. Tags
). But it does work (due to how object initializers work).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With