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 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 中所述 . 为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等) . 为此,您仍然可以使用前面描述的 TypeDescriptor / ConditionalWeakTable 技术和属性扩展,将其隐藏在一个不错的属性下 .
语法仍然会发生变化,因为这意味着issue . 例如, extends 可以被 for 取代,有些人可能感觉更自然,与Java相关性更低 .
Update December 2018 - Roles, Extensions and static interface members
在两个用例中,可以看出先前提案的拆分 . 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;
}
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 < 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
6 回答
不,它们不存在于C#3.0中,也不会在4.0中添加 . 它位于C#的功能要求列表中,因此可能会在将来添加 .
此时,您可以做的最好的是GetXXX样式扩展方法 .
不,他们不存在 .
我知道C#团队正在考虑他们(或者至少是Eric Lippert) - 以及扩展构造者和操作员(这些可能需要一段时间才能让你的头脑清醒,但很酷......)但是,我没有没有看到任何证据表明他们将成为C#4的一部分 .
编辑:他们没有出现在C#5中,截至2014年7月,它看起来也不会出现在C#6中 .
Eric Lippert,微软C#编译团队的首席开发人员,截止到2012年11月,在2009年10月发表了关于此事的博客:
目前,Roslyn编译器仍不支持开箱即用......
到目前为止,扩展属性被认为不足以包含在以前版本的C#标准中 . C# 7 和 C# 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
虽然它仍然只是一个提议的功能,但我们现在可以更清楚地了解它的语法 . 请记住,这也是扩展方法的新语法:
与部分类类似,但在不同的程序集中编译为单独的类/类型 . 请注意,您也可以通过这种方式添加静态成员和运算符 . 如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 中所述 . 为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等) . 为此,您仍然可以使用前面描述的
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 会是这样的:
然后你就可以这样做:
对于 static interface :
在
int
上添加 extension property 并将int
视为IMonoid<int>
:更新(感谢@chaost指出此更新):
资料来源:评论部分https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/
多年来我打开了这个问题并希望能够看到这个问题,我已经停止计算了多少次 .
好吧,最后我们都欢喜!微软将在他们即将发布的C#8版本中介绍这一点 .
所以不要这样做......
我们终于能够这样做......
资料来源:https://blog.ndepend.com/c-8-0-features-glimpse-future/
正如@Psyonity所提到的,您可以使用conditionalWeakTable向现有对象添加属性 . 结合动态ExpandoObject,您可以在几行中实现动态扩展属性:
一个用法示例在xml注释中:
因为我最近需要这个,所以我查看了答案的来源:
c# extend class by adding properties
并创建了一个更动态的版本:
它可能会改进很多(命名,动态而不是字符串),我目前在CF 3.5中使用它与hacky ConditionalWeakTable(https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)