C#有扩展属性吗?

16 浏览
0 Comments

C#有扩展属性吗?

C#是否有扩展属性?

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

admin 更改状态以发布 2023年5月23日
0
0 Comments

不,它们在C# 3.0中不存在,并且不会在4.0中添加。它在C#的功能需求列表上,因此可能在未来日期被添加。

此时,您最好可以使用GetXXX样式的扩展方法。

0
0 Comments

目前Roslyn编译器还不支持它...

到目前为止,扩展属性似乎还不足以被包括在前几个版本的C#标准中。各种C#版本(也许全部?)都曾提出这个提案,但它还没有发布,最重要的是,即使已经有了实现,他们也想做到正确无误。

但也许有一天会有支持...

更新2022:

这个功能似乎仍在讨论中,可以在这里找到相关内容。

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

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

我希望C#很快能提供一个全功能的扩展属性(还有字段),不过这一点只有时间才能告诉我们。

同时,请随时做出贡献,明日的软件将会源于社区。

后处理方法

如果您有权限这样做,您还可以使用像PostSharpMono.Cecil(或类似的代码/IL重写工具)这样的工具在编译后在您的程序集中动态添加属性。

然而,正如一个开发者在上述讨论中所解释的,重写代码不能让编译器知道您的意图,因此它可能无法优化您的代码。作为一种语言特性,结果应该更好。

历史片段

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

但是,还有一个更加有前途的话题,即“扩展一切”,特别是属性和静态类甚至字段。

更新: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的播客中提到的那样,扩展不会有任何状态(因此无法向类添加私有实例成员),这意味着您不能添加与实例关联的私有实例数据。引起这种情况的原因是它将导致内部字典的管理,并可能很困难(内存管理等)。
为此,您仍然可以使用早先描述的 / 技术,并且使用属性扩展将其隐藏在漂亮的属性下。

语法仍可能更改,因为涉及到这个问题。例如,将扩展可能会被取代为,这有些人可能会感觉更自然,也不那么与Java有关。

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

由于存在一些缺点,扩展一切并没有成为C# 8.0的一部分,这些缺点在GitHub ticket的末尾进行了说明。因此,进行了改进设计的探索。在这里,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 上添加一个扩展属性,并将 int 视为 IMonoid

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

0