944 Stimmen

Verfügt C# über Erweiterungseigenschaften?

Verfügt C# über Erweiterungseigenschaften?

Kann ich zum Beispiel eine Erweiterungseigenschaft hinzufügen zu DateTimeFormatInfo genannt. ShortDateLongTimeFormat was Folgendes ergeben würde ShortDatePattern + " " + LongTimePattern ?

21 Stimmen

Ich wollte eine Erweiterungsmethode namens IsNull für Nullable<T> hinzufügen, die einfach ! HasValue zurückgibt. .IsNull() ist auf jeden Fall weniger hübsch als .IsNull

1 Stimmen

Ich finde dies nützlich für trinäre Operatoren ?

2 Stimmen

Ich wollte, dass dies die Java's enum s, die Eigenschaften und Methoden haben können. C#s enum s können keine Eigenschaften oder Methoden haben, aber Sie puede Erweiterungsmethoden für sie erstellen. Diese Frage war nützlich für mich, und sollte nicht geschlossen werden.

695voto

Fab Punkte 12827

Im Moment wird es vom Roslyn-Compiler noch nicht unterstützt ...

Bis jetzt wurden die Erweiterungseigenschaften nicht als wertvoll genug angesehen, um in die früheren Versionen des C#-Standards aufgenommen zu werden. C# 7 y C# 8.0 haben diesen Vorschlag als Champion gesehen, aber er wurde noch nicht veröffentlicht, vor allem, weil sie es von Anfang an richtig machen wollen, auch wenn es bereits eine Umsetzung gibt.

Aber es wird ...

Es gibt eine Erweiterungsmitglieder Element im C# 7 Arbeitsliste so dass sie möglicherweise in naher Zukunft unterstützt wird. Der aktuelle Status der Erweiterungseigenschaft ist zu finden unter Github unter dem entsprechenden Punkt .

Es gibt jedoch ein noch vielversprechenderes Thema, nämlich die "alles erweitern" mit dem Schwerpunkt auf besonderen Eigenschaften und statischen Klassen oder sogar Feldern.

Außerdem können Sie einen Workaround verwenden

Wie in dieser Artikel können Sie die TypeDescriptor die Möglichkeit, ein Attribut zur Laufzeit an eine Objektinstanz anzuhängen. Dabei wird jedoch nicht die Syntax der Standardeigenschaften verwendet.
Es ist ein wenig anders als nur syntaktischer Zucker, der die Möglichkeit bietet, eine erweiterte Eigenschaft zu definieren wie
string Data(this MyClass instance) als Alias für die Erweiterungsmethode
string GetData(this MyClass instance) da sie Daten in der Klasse speichert.

Ich hoffe, dass C#7 eine voll ausgestattete Erweiterung alles (Eigenschaften und Felder), aber in diesem Punkt, nur die Zeit wird zeigen.

Und tragen Sie gerne dazu bei, denn die Software von morgen wird von der Gemeinschaft kommen.

Aktualisierung: August 2016

Wie das dotnet-Team veröffentlichte Was ist neu in C# 7.0 und aus einem Kommentar von Mads Torgensen :

Erweiterungseigenschaften: Wir hatten einen (brillanten!) Praktikanten, der sie Sommer als Experiment implementiert, zusammen mit anderen Arten von Erweiterungs Mitglieder. Wir sind weiterhin daran interessiert, aber es ist eine große Veränderung und wir müssen sicher sein, dass es sich lohnt.

Es scheint, dass Erweiterungseigenschaften und andere Mitglieder immer noch gute Kandidaten sind, um in eine zukünftige Version von Roslyn aufgenommen zu werden, aber vielleicht nicht in die Version 7.0.

Aktualisierung: Mai 2017

Die Erweiterungsmitglieder wurde geschlossen als Duplikat von Erweiterung alles Problem die ebenfalls geschlossen ist. Die Hauptdiskussion drehte sich um die Erweiterbarkeit von Typen im weiteren Sinne. Die Funktion wird nun verfolgt hier als Vorschlag und wurde entfernt aus 7,0 Meilenstein .

Update: August, 2017 - C# 8.0 vorgeschlagene Funktion

Es ist zwar immer noch nur ein vorgeschlagen haben wir nun eine klarere Vorstellung davon, wie die Syntax aussehen könnte. Beachten Sie, dass dies auch die neue Syntax für Erweiterungsmethoden sein wird:

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;

Ähnlich wie partielle Klassen, aber als separate Klasse/Typ in einer anderen Assembly kompiliert. Beachten Sie, dass Sie auf diese Weise auch statische Mitglieder und Operatoren hinzufügen können. Wie bereits in Mads Torgensen-Podcast , die Erweiterung hat keinen Status (sie kann also keine privaten Instanzmitglieder zur Klasse hinzufügen), was bedeutet, dass Sie keine privaten Instanzdaten hinzufügen können, die mit der Instanz verknüpft sind . Der Grund dafür ist, dass es bedeuten würde, intern Wörterbücher zu verwalten, und das könnte schwierig sein (Speicherverwaltung usw.). Hierfür können Sie immer noch die TypeDescriptor / ConditionalWeakTable Technik, die zuvor beschrieben wurde, und mit der Eigenschaftserweiterung, versteckt es unter einer schönen Eigenschaft.

Die Syntax kann sich noch ändern, was bedeutet, dass diese Ausgabe . Zum Beispiel, extends könnte ersetzt werden durch for was manche als natürlicher und weniger javabezogen empfinden mögen.

Update Dezember 2018 - Rollen, Erweiterungen und statische Schnittstellenmitglieder

Erweiterung alles hat es nicht in C# 8.0 geschafft, weil einige der Nachteile, die am Ende dieses GitHub-Ticket . Es wurde also untersucht, wie das Design verbessert werden kann. Hier Mads Torgensen erklärt, was sind Rollen und Erweiterungen und wie sie sich unterscheiden:

Rollen ermöglichen die Implementierung von Schnittstellen für bestimmte Werte eines bestimmten Typs. Erweiterungen ermöglichen die Implementierung von Schnittstellen für alle Werte eines gegebenen Typs innerhalb einer bestimmten Coderegion implementiert werden.

Es kann an einer Aufteilung des vorherigen Vorschlags in zwei Anwendungsfälle gesehen werden. Die neue Syntax für die Erweiterung würde so aussehen:

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

dann könnten Sie dies tun:

foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
    WriteLine($"{e.Current:X}");
}

Und für eine statische Schnittstelle :

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

Hinzufügen einer Erweiterungseigenschaft en int und behandeln die int como IMonoid<int> :

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

443voto

JaredPar Punkte 699699

Nein, es gibt sie nicht in C# 3.0 und sie werden auch nicht in 4.0 hinzugefügt werden. Es ist auf der Liste der Funktion will für C # so kann es zu einem späteren Zeitpunkt hinzugefügt werden.

Zu diesem Zeitpunkt ist das Beste, was Sie tun können, GetXXX-Stil Erweiterung Methoden.

274voto

Jon Skeet Punkte 1325502

Nein, die gibt es nicht.

Ich weiß, dass das C#-Team sie zu einem bestimmten Zeitpunkt in Erwägung gezogen hat (oder zumindest Eric Lippert) - zusammen mit Erweiterungskonstruktoren und -operatoren (es kann eine Weile dauern, bis man sie verstanden hat, aber sie sind cool...) Ich habe jedoch keine Hinweise darauf gesehen, dass sie Teil von C# 4 sein werden.


EDIT: Sie erschienen nicht in C# 5, und seit Juli 2014 sieht es auch nicht so aus, als ob sie in C# 6 erscheinen würden.

Eric Lippert der Hauptentwickler des C#-Compiler-Teams bei Microsoft (bis November 2012), bloggte darüber im Oktober 2009:

29voto

Korayem Punkte 11177

Update (Dank an @chaost für den Hinweis auf diese Aktualisierung):

Mads Torgersen: "Extension everything" hat es nicht in C# 8.0 geschafft. Es hat sich, wenn man so will, in einer sehr spannenden Debatte über die weitere Zukunft der Sprache "verfangen", und jetzt wollen wir sicherstellen, dass wir es nicht auf eine Weise hinzufügen, die diese zukünftigen Möglichkeiten behindert. Manchmal ist Sprachdesign ein sehr langes Spiel!"

出典 Kommentarbereich in https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/


Ich habe aufgehört zu zählen, wie oft ich im Laufe der Jahre diese Frage mit der Hoffnung eröffnet habe, sie umgesetzt zu sehen.

Nun, endlich können wir uns alle freuen! Microsoft wird dies in seiner kommenden C# 8 Version einführen.

Anstatt dies zu tun...

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

Wir werden es endlich so machen können...

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

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

11voto

realbart Punkte 2975

Wie @Psyonity bereits erwähnt hat, können Sie die conditionalWeakTable verwenden, um Eigenschaften zu bestehenden Objekten hinzuzufügen. In Kombination mit dem dynamischen ExpandoObject könnten Sie dynamische Erweiterungseigenschaften in wenigen Zeilen implementieren:

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

Ein Anwendungsbeispiel finden Sie in den XML-Kommentaren:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X