协慌网

登录 贡献 社区

C#是否具有扩展属性?

C#是否具有扩展属性?

例如,是否可以向DateTimeFormatInfo添加名为ShortDateLongTimeFormat的扩展属性,该扩展属性将返回ShortDatePattern + " " + LongTimePattern

答案

不,它们在 C#3.0 中不存在,并且不会在 4.0 中添加。它在 C#所需的功能列表中,因此可以在以后的日期添加。

此时,您可以做的最好的事情就是 GetXXX 样式扩展方法。

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

语法仍然可以更改,这暗示了这个问题 。例如, extends可以被替代for其中的一些可能会感觉更自然,更相关的 java 少。

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

扩展并没有将其扩展到 C#8.0,这是因为在GitHub 票证末尾解释了一些缺点。因此,进行了改进设计的探索。 在这里 ,Mads Torgensen 解释了什么是角色和扩展以及它们之间的区别:

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

可以在两个案例中将先前的建议拆分开来。 扩展新语法如下所示:

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

对于静态接口

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

int上添加扩展属性 ,并将int视为IMonoid<int>

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

不,它们不存在。

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

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

微软 C#编译器团队的首席开发人员埃里克 · 利珀特Eric Lippert)于 2012 年 11 月通过博客在 2009 年 10 月对此发表了评论: