Czy C# ma właściwości extension?

Czy C # ma właściwości rozszerzenia?

Na przykład, Czy Mogę dodać właściwość rozszerzenia do DateTimeFormatInfo o nazwie ShortDateLongTimeFormat, która zwróci ShortDatePattern + " " + LongTimePattern?

Author: Adrian Thompson Phillips, 2009-03-06

6 answers

No One nie istnieją w C # 3.0 i nie zostaną dodane w 4.0. Jest na liście poszukiwanych funkcji dla C# , więc może zostać dodana w przyszłości.

W tym momencie najlepsze, co możesz zrobić, to metody rozszerzenia stylu GetXXX.

 389
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 14:33:40

Nie, one nie istnieją.

Wiem, że zespół C# rozważał je w pewnym momencie ( a przynajmniej Eric Lippert był) - wraz z konstruktorami rozszerzeń i operatorami (to może trochę potrwać, ale są fajne...) Nie widziałem jednak żadnych dowodów na to, że będą częścią C # 4.

EDIT: nie pojawiły się w C# 5, a od lipca 2014 wygląda na to, że nie będzie też w C# 6.

Eric Lippert , główny programista na C# zespół kompilatorów w Microsoft do listopada 2012, blog o tym w październiku 2009:

 240
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:16

Na razie nie jest wspierany po wyjęciu z pudełka przez kompilator Roslyn ...

Do tej pory właściwości rozszerzenia nie były postrzegane jako na tyle wartościowe, aby mogły być zawarte w poprzednich wersjach standardu C# (ie 5 i 6).

Ale tak będzie ...

Istnieje Członkowie przedłużający pozycja w lista prac C # 7 więc może być wspierany w najbliższej przyszłości. Aktualny stan właściwości extension można znaleźć na Github w powiązanej pozycji .

Istnieje jednak jeszcze bardziej obiecujący temat, którym jest "rozszerz wszystko" z naciskiem na szczególnie właściwości i klasy statyczne, a nawet pola.

Ponadto możesz użyć obejścia

Jak określono w tym artykule , możesz użyć funkcji TypeDescriptor, aby dołączyć atrybut do instancji obiektu w czasie wykonywania. Nie używa jednak składni standardowych właściwości.
Trochę inaczej. od samego cukru składniowego dodanie możliwości zdefiniowania rozszerzonej właściwości jak
string Data(this MyClass instance) jako alias dla metody rozszerzenia
string GetData(this MyClass instance) ponieważ przechowuje dane do klasy.

Mam nadzieję, że C # 7 dostarczy w pełni funkcjonalne rozszerzenie everything (properties and fields), jednak na tym etapie czas pokaże.

I nie krępuj się, aby wnieść swój wkład, ponieważ oprogramowanie jutra będzie pochodzić od społeczności.

Aktualizacja: Sierpień 2016

Jako zespół dotnet opublikował co nowego w C # 7.0 i z komentarza Madsa Torgensena:

Właściwości rozszerzenia: mieliśmy (genialne!) stażysta lato jako eksperyment, wraz z innymi rodzajami przedłużania członków. Pozostajemy tym zainteresowani, ale to duża zmiana i my trzeba mieć pewność, że warto.

Wydaje się, że extension properties i inni członkowie, są nadal dobrymi kandydatami do włączenia w przyszłe wydanie Roslyn, ale może nie 7.0.

Aktualizacja: Maj 2017

The extension members został zamknięty jako DUPLIKAT extension everything issue która też jest zamknięta. Główna dyskusja dotyczyła szeroko rozumianej rozszerzalności typów. Funkcja jest teraz śledzona tutaj jako propozycja i został usunięty z 7.0 milestone.

Aktualizacja: Sierpień , 2017-C# 8.0 proponowana funkcja

Chociaż nadal pozostaje tylko proponowaną funkcją, mamy teraz jaśniejszy obraz jej składni. Należy pamiętać, że będzie to również nowa składnia metod rozszerzeń:

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;

Podobne do klas częściowych, ale skompilowane jako oddzielna Klasa/typ w innym zestawie. Uwaga w ten sposób można również dodawać statyczne członków i operatorów. Jak wspomniano w Mads torgensen podcast, rozszerzenie nie będzie miało żadnego stanu (więc nie może dodawać członków instancji prywatnych do klasy), co oznacza, że nie będzie można dodawać danych instancji prywatnych połączonych z instancją. Powodem tego jest to, że sugerowałoby to wewnętrzne zarządzanie słownikami i mogłoby być trudne (zarządzanie pamięcią itp...). W tym celu możesz nadal korzystać z TypeDescriptor/ConditionalWeakTable technika opisana wcześniej i z rozszerzeniem właściwości, ukrywa pod ładną posiadłością.

Składnia nadal może ulec zmianie, co implikuje ten problem . Na przykład, extends może zostać zastąpione przez for, co może wydawać się bardziej naturalne i mniej związane z Javą.

 125
Author: Fab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-05 05:17:15

Przestałem liczyć, ile razy w ciągu lat otworzyłem to pytanie z nadzieją, że widziałem to wdrożone.

W końcu wszyscy możemy się cieszyć! Microsoft zamierza wprowadzić to w swoim nadchodzącym wydaniu C # 8. Więc zamiast tego...
public static class IntExtensions
{
   public static bool Even(this int value)
   {
        return value % 2 == 0;
   }
}

W końcu będziemy mogli to zrobić w ten sposób...

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

Źródło: https://blog.ndepend.com/c-8-0-features-glimpse-future/

 17
Author: Korayem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-06 07:00:48

Jak już wspomniałem @Psyonity, możesz użyć conditionalWeakTable, aby dodać właściwości do istniejących obiektów. W połączeniu z dynamicznym ExpandoObject można zaimplementować dynamiczne właściwości rozszerzenia w kilku wierszach:

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

Przykład użycia znajduje się w komentarzach 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
Author: realbart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-29 14:27:25

Ponieważ ostatnio tego potrzebowałem, spojrzałem na źródło odpowiedzi w:

Klasa C# extend przez dodanie właściwości

I stworzył bardziej dynamiczną wersję:

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

Prawdopodobnie można to znacznie poprawić( nazewnictwo, dynamiczne zamiast string), obecnie używam tego w CF 3.5 razem z hacky ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4 )

 2
Author: Psyonity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:23