是否可以动态实现C#接口

时间:2012-09-19 14:27:05

标签: c#

可以在C#中动态实现接口而不使用反射发出代码,也许可以借助DLR。

我的意思是创建一个允许我们执行以下操作的工厂:

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

罗斯林的方式。

2 个答案:

答案 0 :(得分:1)

我可能错了,但你似乎在寻找Mixins。

它们在C#中没有得到官方支持,但幸运的是the re-mix project(重新动作的一部分)

我过去曾经使用它并且效果很好,这是一个例子:

/// <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))
        {

        }
    }

请注意,虽然INPCTester类没有实现INotifyPropertyChanged,但它可以被转换为它并被视为它。

高级用法允许您在应用程序的生命周期内修改新创建的对象的类型。

答案 1 :(得分:0)

  

可以在C#中动态实现接口而不使用反射发出代码,也许可以借助DLR。

是的,我会这么认为。比尔瓦格纳有一篇名为Implementing Dynamic Interfaces的文章。它演示了如何使用IDynamicMetaObjectProvide接口,特别是DynamicMetaObject类来推送自己的动态对象。然而,这是一个有点复杂的概念,在某些时候,它需要一些反思来将接口的成员连接到相应的DLR表示。

您不能使用现有的动态对象,如ExpandoObject,因为无法动态更改已实现的接口(实际上只有一个接口)。