Question Est-ce que C # a des propriétés d'extension?


Est-ce que C # a des propriétés d'extension?

Par exemple, puis-je ajouter une propriété d'extension à DateTimeFormatInfo appelé ShortDateLongTimeFormat qui reviendrait ShortDatePattern + " " + LongTimePattern?


608
2018-03-06 14:30


origine


Réponses:


Non, ils n'existent pas en C # 3.0 et ne seront pas ajoutés en 4.0. C'est sur la liste des fonctionnalités souhaitées pour C # afin qu'il puisse être ajouté à une date ultérieure.

À ce stade, le mieux que vous pouvez faire est des méthodes d'extension de style GetXXX.


382
2018-03-06 14:33



Non, ils n'existent pas.

Je sais que l'équipe C # les considérait à un moment donné (ou du moins Eric Lippert l'était) - avec les constructeurs et les opérateurs d'extension (ceux-ci peuvent prendre un peu de temps pour tourner la tête, mais sont cool ...). Je n'ai vu aucune preuve qu'ils feraient partie du C # 4.

EDIT: Ils n'apparaissaient pas dans le C # 5, et en juillet 2014, il ne semble pas que ce soit dans le C # 6 non plus.

Eric Lippert, le développeur principal de l'équipe de compilation C # de Microsoft jusqu'en novembre 2012, a écrit un blog à ce sujet en octobre 2009:


238
2018-03-06 14:34



Pour le moment, il n'est toujours pas supporté par le compilateur Roslyn ...

Jusqu'à présent, les propriétés d'extension n'étaient pas considérées comme assez importantes pour être incluses dans les versions précédentes de la norme C # (c.-à-d. 5 et 6).

Mais ça va ...

Il y a un membres de l'extension article dans le C # 7 liste de travail donc il peut être soutenu dans un proche avenir. Le statut actuel de la propriété d'extension peut être trouvé sur Github sous la rubrique associée.

Cependant, il y a un sujet encore plus prometteur qui est le "tout étendre" avec un accent particulier sur les propriétés et les classes statiques ou même les champs.

De plus, vous pouvez utiliser une solution de contournement

Comme spécifié dans cette article, vous pouvez utiliser le TypeDescriptor possibilité d'attacher un attribut à une instance d'objet lors de l'exécution. Cependant, il n'utilise pas la syntaxe des propriétés standard.
C'est un peu différent du sucre syntaxique qui ajoute une possibilité de définir une propriété étendue comme
string Data(this MyClass instance) comme un alias pour la méthode d'extension
string GetData(this MyClass instance) comme il stocke des données dans la classe.

J'espère que C # 7 fournira une extension complète (propriétés et champs), mais sur ce point, seul le temps nous le dira.

Et n'hésitez pas à contribuer car le logiciel de demain viendra de la communauté.

Mise à jour: août 2016

Comme l'équipe dotnet a publié Quoi de neuf dans C # 7.0 et d'un commentaire de Mads Torgensen:

Propriétés d'extension: nous avons eu un (brillant!) Stagiaire les mettre en œuvre   l'été comme expérience, avec d'autres types d'extension   membres. Nous restons intéressés par cela, mais c'est un grand changement et nous   besoin de se sentir confiant que ça en vaut la peine.

Il semble que les propriétés d'extension et d'autres membres, sont encore de bons candidats à inclure dans une future version de Roslyn, mais peut-être pas le 7.0.

Mise à jour: mai 2017

Les membres de l'extension a été fermé en double extension tout problème qui est fermé aussi. La discussion principale portait en fait sur l'extensibilité du type au sens large. La fonctionnalité est maintenant suivie ici comme une proposition et a été retiré de 7.0 étape.

Mise à jour: août 2017 - Fonctionnalité proposée C # 8.0

Alors qu'il ne reste encore qu'un proposé caractéristique, nous avons maintenant une vision plus claire de ce que serait sa syntaxe. Gardez à l'esprit que ce sera la nouvelle syntaxe pour les méthodes d'extension:

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;

Similaire aux classes partielles, mais compilé en tant que classe / type distinct dans un assembly différent. Notez que vous pourrez également ajouter des membres statiques et des opérateurs de cette façon. Comme mentionné dans Podcast de Mads Torgensen, l'extension n'aura aucun état (elle ne peut donc pas ajouter de membres d'instance privée à la classe) ce qui signifie que vous ne pourrez pas ajouter de données d'instance privées liées à l'instance. La raison invoquée pour cela est qu'elle impliquerait de gérer des dictionnaires internes et cela pourrait être difficile (gestion de la mémoire, etc ...). Pour cela, vous pouvez toujours utiliser le TypeDescriptor/ConditionalWeakTable technique décrite précédemment et avec l'extension de la propriété, le cache sous une belle propriété.

La syntaxe est toujours sujette à changement, comme l'implique cette problème. Par exemple, extends pourrait être remplacé par for Certains peuvent se sentir plus naturel et moins java.


108
2018-01-24 13:22



J'ai arrêté de compter combien de fois au cours des années j'ai ouvert cette question avec l'espoir d'avoir vu cela mis en œuvre.

Enfin, nous pouvons tous nous réjouir! Microsoft va introduire cela dans leur prochaine version C # 8.

Alors au lieu de faire ça ...

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

Nous serons enfin capables de le faire comme ça ...

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

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


17
2017-12-04 12:27



Comme @Psyonity mentionné, vous pouvez utiliser le conditionnelWeakTable pour ajouter des propriétés aux objets existants. Combiné avec ExpandoObject dynamique, vous pouvez implémenter des propriétés d'extension dynamique en quelques lignes:

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 exemple d'utilisation est dans les commentaires 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



Parce que j'ai récemment eu besoin de cela, j'ai regardé la source de la réponse dans:

c # étend la classe en ajoutant des propriétés

et créé une version plus dynamique:

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

Il peut probablement être amélioré beaucoup (nommage, dynamique au lieu de chaîne), je l'utilise actuellement dans CF 3.5 avec un hacky ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)


2
2018-01-12 15:33