2

It is possible dynamically implement an interface in C# without emitting code using reflection, maybe with the help of DLR.

I mean create a factory that allow us to do the following:

      IComparable comparable = factory.Create<IComparable>();

Either Roslyn way.

8
  • That sounds a bit lick what mocking frameworks do to me... Commented Sep 19, 2012 at 14:28
  • 2
    What should it do? Should the methods do nothing? Should they take delegates for what the methods do? Should they be given a class that has the methods but doesn't implement the interface? Should it find some random class that does implement the interface? Commented Sep 19, 2012 at 14:29
  • Do you mean, without having a concrete implementation of IComparable registered or linked in some way? Commented Sep 19, 2012 at 14:31
  • 1
    @Servy, lets call that Inversion Of Functionality Commented Sep 19, 2012 at 14:33
  • The point of the DLR is that you at run-time can modify the type by adding methods and properties. However, it seems that your once your object has been created it is no longer "dynamic". Mocking frameworks already can do that but they will do it by emitting code, not using the DLR. Commented Sep 19, 2012 at 14:33

2 Answers 2

1

I may be wrong, but it you seem to be looking for Mixins.

They are not officially supported in C#, but fortunately there's the re-mix project (part of re-motion)

I've used it in the past and it works well, here's an example:

/// <summary>
    /// This <see cref="Mixin"/> is used to "automatically" implement <see cref="INotifyPropertyChanged"/> to a target class.
    /// <para>It will also override <c>ToString()</c> to show it's possible.</para>
    /// </summary>
    /// <example>This example adds <see cref="INotifyPropertyChanged"/> to <see cref="INPCTester"/> 
    /// <code>
    /// [ImplementsINPC]
    /// public class INPCTester
    /// {
    ///     private string m_Name;
    ///     public string Name
    ///     {
    ///         get { return m_Name; }
    ///         set
    ///         {
    ///             if (m_Name != value)
    ///             {
    ///                 m_Name = value;
    ///                 ((ICustomINPC)this).RaisePropertyChanged("Name");
    ///             }
    ///         }
    ///     }
    /// }
    /// 
    /// class Program
    /// {
    ///     static void Main(string[] args)
    ///     {
    ///         INPCImplementation();
    ///     }
    ///     
    ///     static void INPCImplementation()
    ///     {
    ///         Console.WriteLine("INPC implementation and usage");
    ///
    ///         var inpc = ObjectFactory.Create{INPCTester}(ParamList.Empty);
    ///
    ///         Console.WriteLine("The resulting object is castable as INPC: " + (inpc is INotifyPropertyChanged));
    ///
    ///         ((INotifyPropertyChanged)inpc).PropertyChanged += inpc_PropertyChanged;
    ///
    ///         inpc.Name = "New name!";
    ///         Console.WriteLine(inpc.ToString());
    ///         ((INotifyPropertyChanged)inpc).PropertyChanged -= inpc_PropertyChanged;
    ///         Console.WriteLine();
    ///     }
    /// }
    /// 
    /// //Outputs: 
    /// //
    /// //INPC implementation and usage
    /// //The resulting object is castable as INPC: True
    /// //Hello, world! Property's name: Name
    /// //Modified tostring!
    /// </code>
    /// </example>    
    /// <remarks>
    /// The <see cref="ImplementsINPCAttribute"/> is syntactic sugar for 
    /// <para>   <c>[Uses(typeof(INotifyPropertyChangedMixin))]</c> on top of the target class</para>
    /// <para>Which is equivalent to: </para>
    /// <para>   <c>[assembly: Mix(typeof(INPCTester), typeof(INotifyPropertyChangedMixin))]</c> outside the namespace.</para>
    /// <para>or <c>[Extends(typeof(INPCTester))]</c> on top of the mixin class</para>
    /// </remarks>
    public class INotifyPropertyChangedMixin : Mixin<object>, ICustomINPC
    {
        public event PropertyChangedEventHandler PropertyChanged;

        /// <inheritdoc />
        public void RaisePropertyChanged(string prop)
        {
             PropertyChangedEventHandler handler = this.PropertyChanged;
             if (handler != null)
             {
                 handler(this, new PropertyChangedEventArgs(prop));
             }
        }

        /// <inheritdoc />
        [OverrideTarget]
        public new string ToString()
        {
            return "Modified tostring!";
        }
    }

    public class ImplementsINPCAttribute : UsesAttribute 
    {
        public ImplementsINPCAttribute()
            : base(typeof(INotifyPropertyChangedMixin))
        {

        }
    }

Please notice that while the INPCTester class does not implement INotifyPropertyChanged, it can be casted to it and treated as if it did.

Advanced usage allows you to modify types for newly created objects during the lifetime of the application.

Sign up to request clarification or add additional context in comments.

1 Comment

OK, thanks, But in some place you have created an object INotifyPropertyChangedMixin and the only way of do that dynamically is emitting code throught reflection and after maybe inject the code.
0

It is possible dynamically implement an interface in C# without emitting code using reflection, maybe with the help of DLR.

Yes, I would think so. Bill Wagner has an article named Implementing Dynamic Interfaces. It demonstrates how you can use IDynamicMetaObjectProvide interface and in particular the DynamicMetaObject class to roll you very own dynamic object. However, it is a somewhat complex concept and at some point it will require some reflection to hook up the members of the interface to the corresponding DLR representation.

You cannot use an already existing dynamic object like ExpandoObject because the implemented interfaces (actually just one interface) cannot be changed dynamically.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.