2

I'm creating a modular type system were one application(host) loads other modules in to a common UI interface, I have also created an API for this and is available for other users to use.

The API in some instances uses interfaces and abstract classes to force the client using the API to implement the specific methods.

I cannot use interfaces for everything as there are some things were I require putting in my own body so the end user does not need to implement all the unnecessary events and methods himself. EG: So I handle the size changing events myself then pass him the size to a function he implements from called SizeChanged were he can handle his program from the size change.

Abstract classes are what I really want to use but I cannot because the controls the user has may need the x:Name specified in XAML and will recieve the error:

The type ... cannot have a Name attribute. Values types and types without a default constructor can be used as items within ResourceDictionary.

The error occurs because an instance of it needs to be created: Inherited Window can not have a name?

The only solution available to me that I know of is to use a regular class with virtual methods that can be overridden and that does work fine but it does not force the user to implement my methods that are required.

Is there anything I can do cleanly such as any public implementable or something?

This is the structure:

API: IContext -> ContextControl -> (Abstract methods)

Module DLL ContextControl(API) -> AppContextControl(Override methods)

Host Application pull's AppContextControl

I know I can tell the module dev to implement an interface as well as this ContextControl that constrains them to implement the interfaces but it would be much more professional for the compiler to tell them.

In the dev module if I instead of inheriting from ContextControl I implement IContext then I lose all the default bodys and the module dev gotta implement a lot lot more.

Cheers.

Community
  • 1
  • 1
Xela
  • 2,322
  • 1
  • 17
  • 32
  • Possibly a duplicate of http://stackoverflow.com/questions/2118055/how-to-force-overriding-a-method-in-a-descendant-without-having-an-abstract-bas unless there's some workaround for the xaml-specific part of your problem – Ben Aaronson May 12 '14 at 23:30
  • You say you can't use interfaces, but I'm not quite seeing why you can't employ a `where` constraint for selected parts of your API. – ClickRick May 12 '14 at 23:48
  • @ClickRick So your saying that will allow me to use a interface that contains body with default code in that won't notify me to implement the functions in my API DLL but instead the module dll? :/ – Xela May 13 '14 at 00:39

5 Answers5

1

The two ways you've described - interfaces and abstract classes - are (as I'm sure you know) the recommended ways to do what you're describing, at least, if you want to enforce the implementation at compile-time.

The only other way I'm aware of is to provide a default implementation that throws a NotImplementedException(). That'll give you a run-time error, but nothing at compile-time, unfortunately.

Ken Smith
  • 20,305
  • 15
  • 100
  • 147
  • I'v thought about this but unfortunately I require something at compile time so the end user can see he is not implementing something. There are to many issues at run time depending on how experienced the module creator is, e.g. he might try catch all errors and not log them etc.. and wonder why his application is not running correctly. – Xela May 12 '14 at 23:30
1

This may or may not be applicable in your specific situation, but another possible way to get around your limitation is to use a Strategy pattern.

Instead of having the user override members, have them pass in parameters containing the functionality to the constructor. This could either be as delegates or as specific classes you create for the purpose.

Ben Aaronson
  • 6,955
  • 2
  • 23
  • 38
0

Can't you use a combination of inheritance and interfaces? In other words, create virtual methods for the methods that can be overridden and use interfaces to implement methods that must be overridden?

Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • If it wasn't modular yes. I was really only wanting the module developer to inherit from one class from the API as the base app. If he is required to inherit from one class and also implement an interface from the API he might forget to implement it resulting in no compile-time errors but his application wont function correctly. – Xela May 12 '14 at 23:42
  • @Xela -- See if [this article](http://msdn.microsoft.com/en-us/library/ms173157.aspx) can help you and this [SO Question](http://stackoverflow.com/questions/2772627/force-the-use-of-interface-instead-of-concrete-implementation-in-declaration-n#answer-2772693) – Icemanind May 12 '14 at 23:50
  • I don't think so as it does not allow me to specify default code int he body? Iv updated my question a bit anyway. – Xela May 13 '14 at 00:40
0

I recently have a similar problem (dnt know it will help in your case). where i have to generate errors at compile time instead of Runtime, with generic functionality. the approach i used was combination of Generics and Interfaces. Examples are...

1) Enum Ex:(C# String enums) Problem was to set things so that i dnt have to implement every code throughout the project and force Constructor.

public abstract class EnumEx<T> where T : EnumEx<T>
{
    private readonly string _displayValue;
    private readonly string _value;

    protected static ReadOnlyCollection<T> EnumExs;

    protected EnumEx(string displayValue, string value)
    {
        _displayValue = displayValue;
        _value = value;
    }

    public string DisplayValue
    {
        get { return _displayValue; }
    }

    public static T FromString(string option)
    {
        foreach (var enumEx in EnumExs.Where(enumEx => enumEx._value == option))
        {
            return enumEx;
        }
        Debug.WriteLine(string.Format("Exception in EnumEX FromString({0})", option));
        return null;
    }

    public override string ToString()
    {
        return _value ?? string.Empty;
    }
}

2) Deep Copy(Generic method to create deep copy of all elements in a collection) + Editable Implementation IEditableObject over custom List

public abstract class CloneAbleBase<T> : ObservableObjectEx, ICloneable, IEditableObject
    where T : DataBase<T>, new()
{
    protected T CurrentData = new T();
    private T _backupData;
    private bool _isInEditMode;

    public object Clone()
    {
        var dataObject = (CloneAbleBase<T>) MemberwiseClone();
        dataObject.CurrentData = CurrentData.Copy();
        return dataObject;
    }

    public void BeginEdit()
    {
        if (_isInEditMode) return;
        _backupData = CurrentData.Copy();
        _isInEditMode = true;
    }

    public void EndEdit()
    {
        if (!_isInEditMode) return;
        _backupData = default(T);
        _isInEditMode = false;
        RaisePropertyChanged(string.Empty);
    }

    public void CancelEdit()
    {
        if (!_isInEditMode) return;
        CurrentData = _backupData;
        RaisePropertyChanged(string.Empty);
    }
}

In similar way you can create base class for your Window or any control, where you need functionality some sort of generic functionality..

Community
  • 1
  • 1
Mujahid Daud Khan
  • 1,983
  • 1
  • 14
  • 23
0

An alternative i can see in your very specific situation is to use interfaces (which, as you said, won't let you inject your own code) and then inherit from the actual type the end user provides and passed in as an interface and inject your own code there at runtime

For example you load all classes implementing IMyPlugin defined as such

public interface IMyPlugin{
   void MyEndUserMethod();
   void YourMethod();
}

User implements a class that inherits from it

public class UserClass:IMyPlugin{
....
}

You want to force your own code instead of YourMethod, then generate a class at runtime that inherits from UserClass and in YourMethod create your own code and call (or not, depending on your need) base on it. Call base on all other method where the user is to provide the implementation.

This is a bit more work for you but it hides all the uglyness from the end user, simply forcing him to implement the interface. For less uglyness make that interface into 2 interface

public interface IPlugin : IUserPlugin,ICreatorPlugin

And be clear to your users that while the classes must implement IPlugin anything from ICreatorPlugin can be left empty.

An even better solution would be to only expose IUserPlugin and do even more work on your side (your runtime class inherits from the user class AND ICreatorPlugin, and then use duck typing to make it into IPlugin).

Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78