首页 文章

C#有扩展属性吗?

提问于
浏览
638

C#有扩展属性吗?

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

6 回答

  • 245

    不,它们不存在于C#3.0中,也不会在4.0中添加 . 它位于C#的功能要求列表中,因此可能会在将来添加 .

    此时,您可以做的最好的是GetXXX样式扩展方法 .

  • 2

    不,他们不存在 .

    我知道C#团队正在考虑他们(或者至少是Eric Lippert) - 以及扩展构造者和操作员(这些可能需要一段时间才能让你的头脑清醒,但很酷......)但是,我没有没有看到任何证据表明他们将成为C#4的一部分 .

    编辑:他们没有出现在C#5中,截至2014年7月,它看起来也不会出现在C#6中 .

    Eric Lippert,微软C#编译团队的首席开发人员,截止到2012年11月,在2009年10月发表了关于此事的博客:

  • 4

    目前,Roslyn编译器仍不支持开箱即用......

    到目前为止,扩展属性被认为不足以包含在以前版本的C#标准中 . C# 7C# 8.0 已将此视为提案冠军,但尚未发布,最重要的是因为即使已经有实施,他们也希望从一开始就做好 .

    但它会......

    C# 7 work list 中有一个 extension members 项目,因此可能会在不久的将来得到支持 . 扩展属性的当前状态可以在Github under the related item找到 .

    然而,有一个更有希望的话题是"extend everything",特别关注特性和静态类甚至字段 .

    此外,您可以使用解决方法

    article中所指定,您可以使用 TypeDescriptor 功能在运行时将属性附加到对象实例 . 但是,它没有使用标准属性的语法 .
    它与语法糖略有不同,增加了定义扩展属性的可能性
    string Data(this MyClass instance) 作为扩展方法的别名
    string GetData(this MyClass instance) 因为它将数据存储到类中 .

    我希望C#7能提供全功能的扩展(属性和字段),但是在这一点上,只有时间会证明 .

    并随意贡献,因为明天的软件将来自社区 .

    Update: August 2016

    正如dotnet团队发表的what's new in C# 7.0以及Mads Torgensen的评论:

    扩展属性:我们有一个(辉煌!)实习生在夏天实施它们作为实验,以及其他类型的扩展成员 . 我们仍然对此感兴趣,但这是一个很大的变化,我们需要确信这是值得的 .

    似乎扩展属性和其他成员仍然是未来发布的Roslyn中的好选择,但可能不是7.0 .

    Update: May 2017

    The extension members已被关闭extension everything issue的副本,该副本也已关闭 . 主要的讨论实际上是广义上的类型可扩展性 . 该功能现在已被跟踪here as a proposal,已从7.0 milestone中删除 .

    Update: August, 2017 - C# 8.0 proposed feature

    虽然它仍然只是一个提议的功能,但我们现在可以更清楚地了解它的语法 . 请记住,这也是扩展方法的新语法:

    public interface IEmployee 
    {
        public decimal Salary { get; set; }
    }
    
    public class Employee
    {
        public decimal Salary { get; set; }
    }
    
    public extension MyPersonExtension extends Person : IEmployee
    {
        private static readonly ConditionalWeakTable<Person, Employee> _employees = 
            new ConditionalWeakTable<Person, Employee>();
    
    
        public decimal Salary
        {
            get 
            {
                // `this` is the instance of Person
                return _employees.GetOrCreate(this).Salary; 
            }
            set 
            {
                Employee employee = null;
                if (!_employees.TryGetValue(this, out employee)
                {
                    employee = _employees.GetOrCreate(this);
                }
                employee.Salary = value;
            }
        }
    }
    
    IEmployee person = new Person();
    var salary = person.Salary;
    

    与部分类类似,但在不同的程序集中编译为单独的类/类型 . 请注意,您也可以通过这种方式添加静态成员和运算符 . 如Mads Torgensen podcastthe extension won't have any state (so it cannot add private instance members to the class) which means you won't be able to add private instance data linked to the instance 中所述 . 为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等) . 为此,您仍然可以使用前面描述的 TypeDescriptor / ConditionalWeakTable 技术和属性扩展,将其隐藏在一个不错的属性下 .

    语法仍然会发生变化,因为这意味着issue . 例如, extends 可以被 for 取代,有些人可能感觉更自然,与Java相关性更低 .

    Update December 2018 - Roles, Extensions and static interface members

    扩展一切都没有进入C#8.0,因为一些缺点被解释为GitHub ticket的结尾 . 因此,有一项改进设计的探索 . Here,Mads Torgensen解释了什么是 roles and extensions 以及它们的区别:

    角色允许在给定类型的特定值上实现接口 . 扩展允许在特定代码区域内的给定类型的所有值上实现接口 .

    在两个用例中,可以看出先前提案的拆分 . new syntax for extension 会是这样的:

    public extension ULongEnumerable of ulong
    {
        public IEnumerator<byte> GetEnumerator()
        {
            for (int i = sizeof(ulong); i > 0; i--)
            {
                yield return unchecked((byte)(this >> (i-1)*8));
            }
        }
    }
    

    然后你就可以这样做:

    foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
    {
        WriteLine($"{e.Current:X}");
    }
    

    对于 static interface

    public interface IMonoid<T> where T : IMonoid<T>
    {
        static T operator +(T t1, T t2);
        static T Zero { get; }
    }
    

    int 上添加 extension property 并将 int 视为 IMonoid<int>

    public extension IntMonoid of int : IMonoid<int>
    {
        public static int Zero => 0;
    }
    
  • 394

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

    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/

  • 136

    正如@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
    
  • 19

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

    c# extend class by adding properties

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

    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中使用它与hacky ConditionalWeakTable(https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4

相关问题