Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use object initializer syntax with an interface

Tags:

c#

.net

interface

Background

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.

The issue

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?

like image 287
John Wu Avatar asked Oct 17 '22 20:10

John Wu


1 Answers

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).

like image 154
mjwills Avatar answered Oct 21 '22 03:10

mjwills