C# 有扩展属性吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/619033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:29:19  来源:igfitidea点击:

Does C# have extension properties?

c#propertiesextension-methods

提问by Svish

Does C# have extension properties?

C# 有扩展属性吗?

For example, can I add an extension property to DateTimeFormatInfocalled ShortDateLongTimeFormatwhich would return ShortDatePattern + " " + LongTimePattern?

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

采纳答案by Fab

For the moment it is still not supported out of the box by Roslyn compiler ...

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

Until now, the extension properties were not seen as valuable enough to be included in the previous versions of C# standard. C# 7and C# 8.0have seen this as proposal champion but it wasn't released yet, most of all because even if there is already an implementation, they want to make it right from the start.

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

But it will ...

但它会...

There is an extension membersitem in the C# 7 work listso it may be supported in the near future. The current status of extension property can be found on Github under the related item.

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

However, there is an even more promising topic which is the "extend everything"with a focus on especially properties and static classes or even fields.

但是,还有一个更有前途的主题,即“扩展所有内容”,重点关注属性和静态类甚至字段。

Moreover you can use a workaround

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

As specified in this article, you can use the TypeDescriptorcapability to attach an attribute to an object instance at runtime. However, it is not using the syntax of the standard properties.
It's a little bit different from just syntactic sugar adding a possibility to define an extended property like
string Data(this MyClass instance)as an alias for extension method
string GetData(this MyClass instance)as it stores data into the class.

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

I hope that C#7 will provide a full featured extension everything (properties and fields), however on that point, only time will tell.

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

And feel free to contribute as the software of tomorrow will come from the community.

并随时做出贡献,因为明天的软件将来自社区。

Update: August 2016

更新:2016 年 8 月

As dotnet team published what's new in C# 7.0and from a comment of Mads Torgensen:

由于 dotnet 团队发布了 C# 7.0 中的新功能以及Mads Torgensen的评论:

Extension properties: we had a (brilliant!) intern implement them over the summer as an experiment, along with other kinds of extension members. We remain interested in this, but it's a big change and we need to feel confident that it's worth it.

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

It seems that extension properties and other members, are still good candidates to be included in a future release of Roslyn, but maybe not the 7.0 one.

似乎扩展属性和其他成员仍然是 Roslyn 未来版本中包含的很好的候选者,但可能不是 7.0 版本。

Update: May 2017

更新:2017 年 5 月

The extension membershas been closed as duplicate of extension everything issuewhich is closed too. The main discussion was in fact about Type extensibility in a broad sense. The feature is now tracked here as a proposaland has been removed from 7.0 milestone.

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

Update: August, 2017 - C# 8.0 proposed feature

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

While it still remains only a proposedfeature, we have now a clearer view of what would be its syntax. Keep in mind that this will be the new syntax for extension methods as well:

虽然它仍然只是一个提议的功能,但我们现在对它的语法有了更清晰的认识。请记住,这也将是扩展方法的新语法:

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;

Similar to partial classes, but compiled as a separate class/type in a different assembly. Note you will also be able to add static members and operators this way. As mentioned in Mads Torgensen podcast, the 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. The reason invoked for that is it would imply to manage internally dictionaries and it could be difficult (memory management, etc...). For this, you can still use the TypeDescriptor/ConditionalWeakTabletechnique described earlier and with the property extension, hides it under a nice property.

类似于部分类,但在不同的程序集中编译为单独的类/类型。请注意,您还可以通过这种方式添加静态成员和运算符。正如Mads Torgensen 播客中提到的,扩展没有任何状态(因此它不能向类添加私有实例成员),这意味着您将无法添加链接到实例的私有实例数据。这样做的原因是它意味着管理内部字典并且可能很困难(内存管理等)。为此,您仍然可以使用前面描述的TypeDescriptor/ConditionalWeakTable技术并通过属性扩展将其隐藏在一个不错的属性下。

Syntax is still subject to change as implies this issue. For example, extendscould be replaced by forwhich some may feel more natural and less java related.

正如这个问题所暗示的那样,语法仍然会发生变化。例如,extends可以替换为forwhich 有些人可能感觉更自然而与 java 相关的更少。

Update December 2018 - Roles, Extensions and static interface members

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

Extension everythingdidn't make it to C# 8.0, because of some of drawbacks explained as the end of this GitHub ticket. So, there was an exploration to improve the design. Here, Mads Torgensen explains what are roles and extensionsand how they differs:

扩展一切都没有使它成为 C# 8.0,因为在这个GitHub 票结束时解释了一些缺点。于是,就有了改进设计的探索。在这里,Mads Torgensen 解释了什么是角色和扩展以及它们有何不同:

Roles allow interfaces to be implemented on specific values of a given type. Extensions allow interfaces to be implemented on all values of a given type, within a specific region of code.

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

It can be seen at a split of previous proposal in two use cases. The new syntax for extensionwould be like this:

在两个用例中的先前提案的拆分中可以看出这一点。扩展新语法如下所示:

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));
        }
    }
}

then you would be able to do this:

那么你就可以做到这一点:

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

And for a static interface:

对于静态接口

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

Add an extension propertyon intand treat the intas IMonoid<int>:

添加扩展属性int和治疗intIMonoid<int>

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

回答by JaredPar

No they do not exist in C# 3.0 and will not be added in 4.0. It's on the list of feature wants for C# so it may be added at a future date.

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

At this point the best you can do is GetXXX style extension methods.

此时你能做的最好的就是 GetXXX 风格的扩展方法。

回答by Jon Skeet

No, they don't exist.

不,它们不存在。

I know that the C# team was considering them at one point (or at least Eric Lippert was) - along with extension constructors and operators (those may take a while to get your head around, but are cool...) However, I haven't seen any evidence that they'll be part of C# 4.

我知道 C# 团队曾经考虑过它们(或者至少 Eric Lippert 是) - 以及扩展构造函数和运算符(这些可能需要一段时间才能理解,但很酷......)但是,我没有没有看到任何证据表明它们将成为 C# 4 的一部分。



EDIT: They didn't appear in C# 5, and as of July 2014 it doesn't look like it's going to be in C# 6 either.

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

Eric Lippert, the Principal Developer on the C# compiler team at Microsoft thru November 2012, blogged about this in October of 2009:

到 2012 年 11 月,Microsoft C# 编译器团队的首席开发人员Eric Lippert于 2009 年 10 月发表了有关此内容的博客:

回答by Psyonity

Because I recently needed this, I looked at the source of the answer in:

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

c# extend class by adding properties

c#通过添加属性扩展类

and created a more dynamic version:

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

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;
    }
}

It can probably be improved a lot (naming, dynamic instead of string), I currently use this in CF 3.5 together with a hacky ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)

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

回答by realbart

As @Psyonity mentioned, you can use the conditionalWeakTable to add properties to existing objects. Combined with the dynamic ExpandoObject, you could implement dynamic extension properties in a few lines:

正如@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());
    }
}

A usage example is in the xml comments:

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

回答by Korayem

Update (thanks to @chaostfor pointing this update out):

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

Mads Torgersen:"Extension everything didn't make it into C# 8.0. It got “caught up”, if you will, in a very exciting debate about the further future of the language, and now we want to make sure we don't add it in a way that inhibits those future possibilities. Sometimes language design is a very long game!"

Mads Torgersen:“在 C# 8.0 中并没有扩展一切。如果你愿意,它在关于语言的未来的非常激动人心的辩论中被“赶上了”,现在我们要确保我们不会以一种抑制这些未来可能性的方式添加它。有时语言设计是一个很长的游戏!”

Source: comments section in https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/

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



I stopped counting how many times over the years I opened this question with hopes to have seen this implemented.

我不再计算多年来我打开这个问题的次数,希望能看到它的实现。

Well, finally we can all rejoice! Microsoft is going to introduce this in their upcoming C# 8 release.

好吧,我们终于可以欢欣鼓舞了!微软将在他们即将发布的 C# 8 版本中引入这一点。

So instead of doing this...

所以,而不是这样做......

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

We'll be finally able to do it like so...

我们终于可以这样了……

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

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

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