c#有扩展属性吗?

例如,我可以添加一个扩展属性的DateTimeFormatInfo称为ShortDateLongTimeFormat将返回ShortDatePattern + " " + LongTimePattern?


当前回答

正如@Psyonity提到的,可以使用conditionalWeakTable向现有对象添加属性。结合动态ExpandoObject,你可以在几行代码中实现动态扩展属性:

using System.Dynamic;
using System.Runtime.CompilerServices;

namespace ExtensionProperties
{
    /// <summary>
    /// Dynamically associates properies to a random object instance
    /// </summary>
    /// <example>
    /// var jan = new Person("Jan");
    ///
    /// jan.Age = 24; // regular property of the person object;
    /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
    ///
    /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies)
    /// Console.WriteLine("Jan drinks too much");
    /// </example>
    /// <remarks>
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// </remarks>
    public static class ObjectExtensions
    {
        ///<summary>Stores extended data for objects</summary>
        private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

        /// <summary>
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// </summary>
        /// <param name="obj">The object the properties are associated with</param>
        /// <returns>A dynamic collection of properties associated with an object instance.</returns>
        public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
    }
}

xml注释中有一个用法示例:

var jan = new Person("Jan");

jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;

if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
    Console.WriteLine("Jan drinks too much");
}

jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection

其他回答

不,它们在c# 3.0中不存在,也不会在4.0中添加。它在c#需要的特性列表中,所以将来可能会添加它。

在这一点上,你能做的最好的是GetXXX样式的扩展方法。

不,他们不存在。

我知道c#团队曾经考虑过它们(或者至少Eric Lippert曾经考虑过)——还有扩展构造函数和操作符(你可能需要一段时间才能理解它们,但是很酷……)然而,我还没有看到任何证据表明它们将成为c# 4的一部分。


编辑:它们没有出现在c# 5中,到2014年7月,看起来也不会出现在c# 6中。

Eric Lippert,微软c#编译器团队2012年11月的首席开发人员,在2009年10月写了一篇博文:

为什么没有扩展属性?-编程中的奇妙冒险

更新(感谢@chaos指出此更新):

Mads Torgersen:“c# 8.0并没有扩展所有东西。如果你愿意的话,它“陷入”了一场关于语言未来发展的非常激动人心的辩论,现在我们想确保我们添加它的方式不会抑制这些未来的可能性。有时候语言设计是一场漫长的游戏!”

来源:https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/的评论部分


我不再计算这些年来我有多少次提出这个问题,希望看到它得到实现。

好吧,我们终于都可以高兴了!微软将在他们即将发布的c# 8版本中引入这个功能。

所以与其这样做…

public static class IntExtensions
{
   public static bool Even(this int value)
   {
        return value % 2 == 0;
   }
}

我们终于可以这样做了…

public extension IntExtension extends int
{
    public bool Even => this % 2 == 0;
}

来源:https://blog.ndepend.com/c-8-0-features-glimpse-future/

因为我最近需要这个,我查看了答案的来源:

通过添加属性来扩展类

并创造了一个更动态的版本:

public static class ObjectExtenders
{
    static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>();

    public static string GetFlags(this object objectItem, string key)
    {
        return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value;
    }

    public static void SetFlags(this object objectItem, string key, string value)
    {
        if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key))
        {
            Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value;
        }
        else
        {
            Flags.GetOrCreateValue(objectItem).Add(new stringObject()
            {
                Key = key,
                Value = value
            });
        }
    }

    class stringObject
    {
        public string Key;
        public string Value;
    }
}

它可能会有很大的改进(命名,动态而不是字符串),我目前在CF 3.5中使用它和一个hack的ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)

正如@Psyonity提到的,可以使用conditionalWeakTable向现有对象添加属性。结合动态ExpandoObject,你可以在几行代码中实现动态扩展属性:

using System.Dynamic;
using System.Runtime.CompilerServices;

namespace ExtensionProperties
{
    /// <summary>
    /// Dynamically associates properies to a random object instance
    /// </summary>
    /// <example>
    /// var jan = new Person("Jan");
    ///
    /// jan.Age = 24; // regular property of the person object;
    /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
    ///
    /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies)
    /// Console.WriteLine("Jan drinks too much");
    /// </example>
    /// <remarks>
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// </remarks>
    public static class ObjectExtensions
    {
        ///<summary>Stores extended data for objects</summary>
        private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

        /// <summary>
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// </summary>
        /// <param name="obj">The object the properties are associated with</param>
        /// <returns>A dynamic collection of properties associated with an object instance.</returns>
        public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
    }
}

xml注释中有一个用法示例:

var jan = new Person("Jan");

jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;

if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
    Console.WriteLine("Jan drinks too much");
}

jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection