Pregunta ¿Tiene C # propiedades de extensión?


¿Tiene C # propiedades de extensión?

Por ejemplo, ¿puedo agregar una propiedad de extensión a DateTimeFormatInfo llamado ShortDateLongTimeFormat que regresaría ShortDatePattern + " " + LongTimePattern?


608
2018-03-06 14:30


origen


Respuestas:


No, no existen en C # 3.0 y no se agregarán en 4.0. Está en la lista de características deseadas para C #, por lo que puede agregarse en una fecha futura.

En este punto, lo mejor que puede hacer es usar métodos de extensión de estilo GetXXX.


382
2018-03-06 14:33



No, ellos no existen.

Sé que el equipo de C # los estaba considerando en un punto (o al menos Eric Lippert), junto con los constructores de extensión y los operadores (puede tomar un tiempo para darse una vuelta, pero son geniales ...) Sin embargo, no lo sé No he visto ninguna evidencia de que sean parte de C # 4.

EDITAR: No aparecieron en C # 5 y, a partir de julio de 2014, tampoco parece que vaya a estar en C # 6.

Eric Lippert, el desarrollador principal en el equipo compilador de C # en Microsoft hasta noviembre de 2012, blogueó sobre esto en octubre de 2009:


238
2018-03-06 14:34



Por el momento, todavía no es compatible con el compilador de Roslyn.

Hasta ahora, las propiedades de extensión no se consideraban lo suficientemente valiosas como para incluirse en las versiones anteriores del estándar C # (es decir, 5 y 6).

Pero será ...

Hay un miembros de extensión artículo en el C # 7 lista de trabajo por lo que puede ser compatible en el futuro cercano. El estado actual de la propiedad de extensión se puede encontrar en Github bajo el elemento relacionado.

Sin embargo, hay un tema aún más prometedor que es el "extender todo" con un enfoque especialmente en propiedades y clases estáticas o incluso campos.

Además, puedes usar una solución alternativa

Como se especifica en este artículo, puedes usar el TypeDescriptor capacidad para adjuntar un atributo a una instancia de objeto en tiempo de ejecución. Sin embargo, no está usando la sintaxis de las propiedades estándar.
Es un poco diferente del azúcar sintáctico que agrega la posibilidad de definir una propiedad extendida como
string Data(this MyClass instance) como un alias para el método de extensión
string GetData(this MyClass instance) ya que almacena datos en la clase.

Espero que C # 7 proporcionará una extensión con todas las funciones (propiedades y campos), sin embargo, en ese punto, solo el tiempo dirá.

Y siéntete libre de contribuir ya que el software del mañana vendrá de la comunidad.

Actualización: agosto de 2016

Como el equipo de dotnet publicó ¿Qué hay de nuevo en C # 7.0 y de un comentario de Mads Torgensen:

Propiedades de extensión: tuvimos un (brillante!) Interno que los implementó   el verano como un experimento, junto con otros tipos de extensión   miembros. Seguimos interesados ​​en esto, pero es un gran cambio y   Necesito estar seguro de que vale la pena.

Parece que las propiedades de extensión y otros miembros siguen siendo buenos candidatos para ser incluidos en una versión futura de Roslyn, pero tal vez no en la versión 7.0.

Actualización: mayo de 2017

Los miembros de la extensión ha sido cerrado como duplicado de extensión todo asunto que está cerrado también. La discusión principal fue de hecho sobre la extensibilidad de tipos en un sentido amplio. La función ahora se rastrea aquí como una propuesta y ha sido eliminado de 7.0 hito.

Actualización: agosto de 2017 - función propuesta C # 8.0

Si bien sigue siendo solo un propuesto característica, ahora tenemos una visión más clara de lo que sería su sintaxis. Tenga en cuenta que esta será la nueva sintaxis para los métodos de extensión también:

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 a las clases parciales, pero compilado como una clase / tipo separado en un ensamblaje diferente. Tenga en cuenta que también podrá agregar miembros estáticos y operadores de esta manera. Como se menciona en Podcast de Mads Torgensen, la extensión no tendrá ningún estado (por lo que no puede agregar miembros de instancia privados a la clase) lo que significa que no podrá agregar datos de instancia privados vinculados a la instancia. La razón invocada para eso es que implicaría administrar internamente diccionarios y podría ser difícil (gestión de memoria, etc.). Para esto, puedes usar el TypeDescriptor/ConditionalWeakTable La técnica descrita anteriormente y con la extensión de la propiedad, la oculta bajo una buena propiedad.

La sintaxis aún está sujeta a cambios, ya que implica esto problema. Por ejemplo, extends podría ser reemplazado por for que algunos pueden sentirse más naturales y menos relacionados con Java.


108
2018-01-24 13:22



Dejé de contar cuántas veces a lo largo de los años abrí esta pregunta con la esperanza de haber visto esto implementado.

Bueno, finalmente todos podemos regocijarnos! Microsoft presentará esto en su próximo lanzamiento C # 8.

Entonces, en lugar de hacer esto ...

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

Finalmente podremos hacerlo así ...

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

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


17
2017-12-04 12:27



Como se menciona @Psyonity, puede usar el conditionalWeakTable para agregar propiedades a los objetos existentes. Combinado con el ExpandoObject dinámico, puede implementar propiedades de extensión dinámica en unas pocas líneas:

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

Un ejemplo de uso está en los comentarios 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

4
2018-04-18 12:54



Como hace poco necesitaba esto, miré la fuente de la respuesta en:

c # extender clase agregando propiedades

y creó una versión más dinámica:

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

Probablemente se puede mejorar mucho (nombrar, dinámico en lugar de cadena), actualmente uso esto en CF 3.5 junto con una hacky ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)


2
2018-01-12 15:33