Есть ли в C # свойства расширения?

Есть ли в C # свойства расширения?

Например, я могу добавить свойство расширения к DateTimeFormatInfoвызываемому, ShortDateLongTimeFormatкоторый будет возвращать ShortDatePattern + " " + LongTimePattern?

6.03.2009 14:30:44
Я хотел добавить метод расширения с именем IsNull для Nullable <T>, который просто вернется! HasValue. .IsNull () определенно менее красива, чем .IsNull
Ken 3.08.2011 19:02:20
Я считаю это полезным для тринарного оператора?
PedroC88 24.08.2012 17:59:57
Я хотел, чтобы это имитировало Java, enumкоторые могут иметь свойства и методы. В C # enumне может быть свойств или методов, но вы можете создавать методы расширения для них. Этот вопрос был полезен для меня и не должен быть закрыт.
Ian McLaird 25.09.2014 13:51:39
Хотя, как говорили многие люди, в настоящее время нет никаких планов по добавлению этого в язык, нет никаких причин, по которым это невозможно сделать. Тот факт, что F # имеет для меня не только свойства расширения, но и статические расширения, доказывает, что это по крайней мере хорошая идея.
Richiban 21.10.2014 09:36:37
Там должно быть сделано один
Rootel 6.08.2016 08:21:20
6 ОТВЕТОВ
РЕШЕНИЕ

На данный момент он все еще не поддерживается из коробки компилятором Roslyn ...

До сих пор свойства расширения не рассматривались как достаточно ценные, чтобы их можно было включить в предыдущие версии стандарта C #. C # 7 и C # 8.0 считают это чемпионом предложения, но оно еще не было выпущено, прежде всего потому, что, даже если уже есть реализация, они хотят сделать это с самого начала.

Но это будет ...

В рабочем списке C # 7 есть элемент расширения, поэтому он может быть поддержан в ближайшем будущем. Текущий статус свойства extension можно найти на Github под соответствующим элементом .

Тем не менее, есть еще более многообещающая тема: «Расширить все» с акцентом на свойствах, статических классах или даже полях.

Кроме того, вы можете использовать обходной путь

Как указано в этой статье , вы можете использовать TypeDescriptorвозможность прикрепить атрибут к экземпляру объекта во время выполнения. Однако он не использует синтаксис стандартных свойств.
Это немного отличается от простого синтаксического сахара, добавляющего возможность определять расширенное свойство, например,
string Data(this MyClass instance)в качестве псевдонима для метода расширения, так
string GetData(this MyClass instance)как оно хранит данные в классе.

Я надеюсь, что C # 7 обеспечит полнофункциональное расширение всего (свойств и полей), однако на данный момент только время покажет.

И не стесняйтесь вносить свой вклад, поскольку программное обеспечение завтрашнего дня придет от сообщества.

Обновление: август 2016

Как команда dotnet опубликовала, что нового в C # 7.0 и из комментария Мадса Торгенсена :

Свойства расширения: у нас (блестящий!) Молодой специалист реализовал их летом в качестве эксперимента вместе с другими типами членов расширения. Мы по-прежнему заинтересованы в этом, но это большое изменение, и мы должны быть уверены, что оно того стоит.

Кажется, что свойства расширения и другие члены все еще являются хорошими кандидатами для включения в будущий выпуск Roslyn, но, возможно, не в 7.0.

Обновление: май 2017

Расширение членов было закрыто как дубликат расширения все проблемы, которые тоже закрыты. Основное обсуждение было на самом деле о расширяемости типов в широком смысле. Эта функция теперь отслеживается здесь как предложение и удалена из этапа 7.0 .

Обновление: август 2017 г. - C # 8.0 предлагаемая функция

Хотя это все еще остается только предложенной функцией, теперь у нас есть более четкое представление о том, каким будет ее синтаксис. Имейте в виду, что это будет новый синтаксис и для методов расширения:

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 , расширение не будет иметь никакого состояния (поэтому оно не может добавлять частные элементы экземпляра в класс), что означает, что вы не сможете добавлять частные данные экземпляра, связанные с экземпляром . Причиной этого является то, что это подразумевает управление внутренними словарями, и это может быть затруднительно (управление памятью и т. Д.). Для этого вы все еще можете использовать метод TypeDescriptor/ ConditionalWeakTable, описанный ранее, и с расширением свойства скрывает его под хорошим свойством.

Синтаксис все еще может быть изменен, поскольку подразумевает эту проблему . Например, extendsможет быть заменено тем, forчто некоторые могут чувствовать себя более естественно и менее связаны с Java.

Обновление декабря 2018 года - роли, расширения и статические члены интерфейса

Расширение все не дошло до C # 8.0, из-за некоторых недостатков, объясненных как конец этого билета GitHub . Итак, было проведено исследование для улучшения дизайна. Здесь Мадс Торгенсен объясняет, что такое роли и расширения и чем они отличаются:

Роли позволяют реализовывать интерфейсы для определенных значений данного типа. Расширения позволяют реализовывать интерфейсы для всех значений данного типа в пределах определенной области кода.

Это можно увидеть при разделении предыдущего предложения в двух случаях использования. Новый синтаксис для расширения будет выглядеть так:

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

И для статического интерфейса :

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

Добавить свойство расширения на intи лечить , intкак IMonoid<int>:

public extension IntMonoid of int : IMonoid<int>
{
    public static int Zero => 0;
}
346
30.11.2018 19:11:06
Это один из самых полезных ответов, которые я когда-либо использовал на StackExchange. Постоянно обновляется со статусом и держит всех в курсе, что возвращается к этому, обеспечивая прочные ссылки на обсуждение и историю.
bdrelling 31.01.2019 05:07:01
Это потрясающе, что вы держите это в курсе - спасибо
David Thielen 13.02.2019 16:20:56

Нет, они не существуют в C # 3.0 и не будут добавлены в 4.0. Он находится в списке желаний для C #, поэтому он может быть добавлен в будущем.

На данный момент лучшее, что вы можете сделать, - это методы расширения стиля GetXXX.

436
6.03.2009 14:33:40
Аналогично с общими свойствами: вы должны использовать синтаксис «GetXXX <>».
Jay Bazuzi 6.03.2009 15:39:13
хорошо, я так и думал. @ Джей, да, я тоже это ненавижу, хе-хе. Особенно невозможность иметь общий индексатор ... вздох
Svish 6.03.2009 17:51:36
Ссылка на список функций хочет?
Dan Esparza 22.10.2010 05:45:08
А как насчет версии 6.0 и 7.0?
Falk 13.03.2019 10:50:36
Какие-либо обновления по этому вопросу к 2020 году?
Chad 16.01.2020 03:35:29

Нет, их не существует.

Я знаю, что команда C # рассматривала их в какой-то момент (или, по крайней мере, Эрик Липперт) - вместе с конструкторами и операторами расширений (это может занять некоторое время, чтобы разобраться, но это круто ...) Однако, у меня нет не видел никаких доказательств того, что они будут частью C # 4.


РЕДАКТИРОВАТЬ: они не появились в C # 5, и по состоянию на июль 2014 года, похоже, что это будет в C # 6 тоже.

Эрик Липперт , главный разработчик команды компилятора C # в Microsoft до ноября 2012 года, писал об этом в октябре 2009 года:

264
19.04.2020 17:52:30
Да, и они все еще могут скрывать поле - установка одного свойства может установить два свойства внизу или наоборот. (Представьте себе что-нибудь с обычным свойством Size и свойствами расширения Width / Height, или наоборот.) Хотя, я подозреваю, они были бы более полезны как доступные только для чтения.
Jon Skeet 6.03.2009 14:46:07
Вы не можете привязать методы расширения ... возможность добавлять свои собственные свойства для привязки данных может быть полезной во многих ситуациях.
Nick 6.03.2009 14:46:10
@leppie - Значение расширений свойств принесло бы наибольшую пользу свойствам bool и string. Избавление от ()в конце гораздо более читабельно. Я лично знаю, что по крайней мере 90% написанных мной расширений относятся к этим двум типам.
Code Maverick 31.10.2013 16:54:48
Чтобы привести пример того, почему это было бы полезно, у меня есть модель EFCF. В некоторых классах у меня есть свойства только для чтения, которые я использую для возврата отформатированной информации: FullName= FirstName + LastName, ShortName= FirstName + LastName[0]. Я хотел бы добавить больше этих свойств, но я не хочу «портить» реальные классы. В этом случае свойство расширения, предназначенное только для чтения, идеально подходит, потому что я могу добавить функциональность, сохранить основной класс в чистоте и по-прежнему предоставлять информацию, которую я хочу предоставить в пользовательском интерфейсе.
Gup3rSuR4c 20.02.2014 04:54:46
@JonSkeet: Вы правы, в итоге я сделал то, что хотел, создав собственный класс, обернув все соответствующие методы и свойства запечатанного класса, и предоставив, static implicit operator FileInfo(FileInfoEx fex)который возвращает мой содержащийся объект FileInfo. Это позволяет мне обрабатывать FileInfoEx так, как если бы он наследовал от FileInfo, даже если этот класс запечатан.
Steve L 2.10.2014 21:28:51

Поскольку я недавно нуждался в этом, я посмотрел на источник ответа в:

C # расширить класс, добавив свойства

и создал более динамическую версию:

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

Вероятно, это может быть значительно улучшено (наименование, динамическое, а не строковое), в настоящее время я использую это в CF 3.5 вместе с хакерским ConditionalWeakTable ( https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4 )

1
23.05.2017 12:26:23
Извините, но хотя это выглядит очень тщательно, это не имеет ничего общего со свойствами расширения, а только показывает методы расширения.
Viking 12.03.2018 09:39:38

Как упоминалось @Psyonity, вы можете использовать conditionalWeakTable для добавления свойств к существующим объектам. В сочетании с динамическим ExpandoObject вы можете реализовать свойства динамического расширения в несколько строк:

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

Пример использования в комментариях 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
8
29.05.2017 14:27:25
Лучший ответ
N73k 21.06.2019 04:16:51

Обновление (спасибо @chaost за указание на это обновление):

Мэдс Торгерсен: «Расширение - все, что не вошло в C # 8.0. Он попал в« захватывающую »дискуссию о дальнейшем будущем языка, и теперь мы хотим убедиться, что мы этого не делаем». добавьте его таким образом, чтобы помешать этим будущим возможностям. Иногда языковой дизайн - очень длинная игра! »

Источник: раздел комментариев в https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/


Я перестал считать, сколько раз за эти годы я открыл этот вопрос в надежде увидеть, как это будет реализовано.

Ну наконец-то мы все можем порадоваться! Microsoft собирается представить это в своем следующем выпуске C # 8.

Так что вместо этого ...

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

Мы наконец сможем сделать это так ...

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

Источник: https://blog.ndepend.com/c-8-0-features-glimpse-future/

27
18.11.2018 08:13:01
На этой неделе были объявлены возможности C # 8.0, и я, к сожалению, не увидел ничего подобного.
Mateo Torres-Ruiz 15.11.2018 21:56:23
@ MateoTorres-Ruiz Комментарий от 'Mads Torgersen' (C # dev), отвечающий кому-то, спрашивающему об этом (3 дня назад): «Расширение, все не попало в C # 8.0. Он« догнал », если хотите В очень захватывающих дебатах о будущем будущем языка, и теперь мы хотим убедиться, что мы не добавим его таким образом, который ограничивает эти будущие возможности. Иногда языковой дизайн - очень длинная игра! " Чувствует себя плохо .. (Прочтите это по ссылке Korayems, в разделе комментариев)
Chaost 16.11.2018 09:58:13