当前位置:  开发笔记 > 编程语言 > 正文

C#有扩展属性吗?

如何解决《C#有扩展属性吗?》经验,为你挑选了5个好方法。

C#有扩展属性吗?

例如,我可以添加一个扩展属性来DateTimeFormatInfo调用ShortDateLongTimeFormat哪个会返回ShortDatePattern + " " + LongTimePattern



1> JaredPar..:

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

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


链接到功能列表需要?
请参阅GitHub上的功能请求:https://github.com/dotnet/csharplang/issues/192
好的,这就是我的想法.@Jay,是的,我也讨厌那个,呵呵.特别是无法拥有通用索引器......*叹气*
与通用属性类似:您必须使用'GetXXX <>'语法.
那6.0和7.0版本呢?

2> Jon Skeet..:

不,他们不存在.

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

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

微软C#编译团队首席开发人员Eric Lippert于2012年11月在博客中发表了关于此问题的文章:

为什么没有扩展属性? - 编码中的神话般的冒险


您无法绑定到扩展方法...能够为数据绑定添加自己的属性在许多情况下可能会有所帮助.
为了举例说明为什么这会有用,我有一个EFCF模型.在某些类中,我使用只读属性来返回格式化信息:`FullName` =`FirstName + LastName`,`ShortName` =`FirstName + LastName [0]`.我想添加更多这些属性,但我不想"弄脏"实际的类.在这种情况下,扩展属性是只读的,因为我可以添加功能,保持主类清洁,并且仍然暴露我想在UI中公开的信息.
@JonSkeet:你是对的,我最后通过创建自己的类来完成我想做的事情,然后包装所有相关的密封类方法和属性,然后提供`静态隐式运算符FileInfo(FileInfoEx fex)`,它返回我包含的FileInfo对象.这有效地让我将FileInfoEx视为继承自FileInfo,即使该类是密封的.
@leppie - 属性扩展的价值最有利于bool和字符串属性.最后摆脱`()`更具可读性.我个人认识,我写的至少90%的扩展都属于这两种类型.
是的,他们仍然可以隐藏字段 - 设置单个属性可能会在下面设置两个属性,反之亦然.(想象一下具有普通Size属性和Width/Height扩展属性的东西,反之亦然.)我怀疑它们作为只读属性更有用.
另一个例子是扩展一个密封类,我想使用FileInfo,但我想保留一些关于每个文件的额外信息.我不能从FileInfo继承,所以如果我想暴露大部分FileInfo功能,我就会陷入组合,这涉及到大量的方法包装.

3> Fab..:

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

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

但它会......

C#7工作列表中有一个扩展成员项,因此可能在不久的将来支持它.扩展属性的当前状态可以在相关项下的Github上找到.

然而,有一个更有希望的主题是"扩展一切",重点是特别是属性和静态类甚至字段.

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

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

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

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

更新:2016年8月

随着dotnet团队发布了C#7.0中的新内容以及Mads Torgensen的评论:

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

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

更新:2017年5月

扩展成员已被关闭作为扩展的所有问题的副本也被关闭.主要的讨论实际上是广义上的类型可扩展性.此功能现在作为提案进行跟踪,已从 7.0里程碑中删除.

更新:2017年8月 - C#8.0提议的功能

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

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 _employees = 
        new ConditionalWeakTable();


    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播客中所述,扩展将不具有任何状态(因此它无法将私有实例成员添加到类中),这意味着您将无法添加链接到该实例的私有实例数据.为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等).为此,您仍然可以使用前面描述的TypeDescriptor/ ConditionalWeakTable技术和属性扩展,将其隐藏在一个不错的属性下.

语法仍然会发生变化,因为这意味着这个问题.例如,extends可以替换为for某些可能感觉更自然且与Java相关的更少.

更新2018年12月 - 角色,扩展和静态接口成员

扩展一切都没有进入C#8.0,因为一些缺点被解释为这个GitHub票的结束.因此,有一项改进设计的探索.在这里,Mads Torgensen解释了什么是角色和扩展以及它们的区别:

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

在两个用例中,可以看出先前提案的拆分.扩展新语法如下:

public extension ULongEnumerable of ulong
{
    public IEnumerator 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}");
}

对于静态接口:

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

添加扩展属性int和治疗intIMonoid:

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


这是我在StackExchange上遵循的最有用的答案之一.不断更新状态并让每个人都知道回到此状态,为讨论和历史提供可靠的链接.
你保持最新状态真是太棒了 - 谢谢

4> Korayem..:

更新(感谢@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/


本周[C#8.0功能](https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/)已经公布,不幸的是我没有看到任何这些.

5> realbart..:

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

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

namespace ExtensionProperties
{
    /// 
    /// Dynamically associates properies to a random object instance
    /// 
    /// 
    /// 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");
    /// 
    /// 
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// 
    public static class ObjectExtensions
    {
        ///Stores extended data for objects
        private static ConditionalWeakTable extendedData = new ConditionalWeakTable();

        /// 
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// 
        /// The object the properties are associated with
        /// A dynamic collection of properties associated with an object instance.
        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

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有