tags:

views:

65

answers:

3

I know the title is a bit confusing but bare with me. (I'm up for suggestions on a new title lol) I'm writing a TemplateEngine that will allow me to use my own markup in text based files. I'm wanting to add controls as plugins as the application matures. Currently i've got a structure like the following:

interface IControl
    string Id
    object Value

class Label : IControl
    string Id
    string Value

class Repeater : IControl
    string Id
    List<IControl> Value

Now you'll see the strange part right away in the Repeater class with the Value property. I was hoping that having the Value type as object in the interface would allow me the flexibility to expand the controls as i go along. The compiler doesn't like this and for good reason i guess.

Bottom line: I'm trying to get all control classes to implement the same interface but have different types for the Value property.

Does anyone have any suggestions how to accomplish this?

Note: Please don't go into suggesting things like use Spark View Engine for templating. There is a reason i'm creating extra work for myself.

+3  A: 

Normally the Repeater would implement something different, like an IItemsControl for example.

EDIT 1

(removed for brevity)

EDIT 2

Ah okay, you can always use explicit interface implementation of course:

interface IControl
{
    string Id { get; set; }
    object Value { get; set; }
}

class Label : IControl
{
    public string Id { get; set; }
    public string Value { get; set; }

    object IControl.Value
    {
        get { return this.Value; }
        set { this.Value = (string)value; }
    }
}

class Repeater : IControl
{
    public string Id { get; set; }
    public IList<IControl> Value { get; set; }

    object IControl.Value
    {
        get { return this.Value; }
        set { this.Value = (IList<IControl>)value; }
    }
}
herzmeister der welten
yeah this is the only other route i could think of
used2could
+1 for figuring out what the crap i was even talking about
used2could
lolz ... just training my clairvoyance skills :-> ... I updated my answer with an example.
herzmeister der welten
Great example Herzm!!
used2could
This may not work always. The explicit definition of properties, if different from local properties, then would be dangerous. See my example.
Nayan
+1  A: 

No, the compiler doesn't allow same name fields to be of different data types other than what is defined in the interface in derived classes.

The properties (since no fields are allowed in interface) should be implemented in the deriving classes and they need to have same data type. So, you cannot probably do it with properties without explicit declaration.

However, if you make Value to be returned by a function, then it works, but you need to check the return type because the return types should match for the function, otherwise you will get error that interface's function was not implemented.

    interface IControl
    {
        object Value();
    }
    class A : IControl
    {
        string m_value = string.Empty;
        public object Value() { return m_value; }
    };
    class B : IControl
    {
        List<IControl> m_value = new List<IControl>();
        public object Value() { return m_value; }
    };
    ....
    object o = new B().Value();
    if (o is List<IControl>)
        MessageBox.Show("List");

[Update]
You have to be careful if explicitly defining the body of the properties. Having one name for two properties would be dangerous if implementation is not done carefully.

These two properties if contain different definition, it would be unexplainable for the final use of the interface and classes.

        public IList<IControl> Value
        object IControl.Value

See this example:

    ...
    class Repeater : IControl
    {
        List<IControl> m_Value = new List<IControl>();
        public IList<IControl> Value
        {
            get { return this.m_Value; }
            set { this.m_Value = (IList<IControl>)value; }
        }
        object IControl.Value
        {
            get
            {
                return this.m_Value;
            }
            set
            {
                this.m_Value = new List<IControl>();
                this.m_Value.Add(new Label());
                this.m_Value.AddRange((List<IControl>)value);
            }
        }
    }
    ...
    Repeater b = new Repeater();
    IControl i = b;
    List<IControl> list = new List<IControl>();
    list.Add(new Repeater());
    i.Value = list;

You can observe that the list container in Repeater will have different values when data is added via IControl (because of the explicit definition of IContainer.Value).

Nayan
+1 Thanks for pointing out the concern of explicitly defining a property.
used2could
+1  A: 

you could also use generics:

interface IControl<T> 
{
    string ID{get;set;}
    T Value{get;set;}
}

class SomeControl : IControl<string>
{
    public string ID{get;set}
    public string Value{get;set;}
}

class SomeOtherControl : IControl<int>
{
    public string ID{get;set}
    public int Value{get;set;}
}

I like this better than the explicit interface idea if it's just one return value that needs to change. However, I think if you had several properties that each would return a different type, you wouldn't want to have IControl. At least, I wouldn't. In that case I would recommend the explicit interfaces.

Of course, this wouldn't work if you didn't have access to the source of IControl.

Edit: had a typo. Fixed

Joel
yes we could use generics too, I haven't thought about it because I'm brainwashed by UI design tools which mostly don't like controls with generic type parameters. ;-)
herzmeister der welten
I thought about generics and it was turned down by management. Something about it not being easy for developers who aren't familiar with the library's details... (I just collect a check)
used2could