Методы Расширения C# на “участниках”

У меня есть некоторые дополнительные методы, которые могли использоваться как это:

MyType myObject; 
string displayName = myObject.GetDisplayName(x => x.Property);

Проблема здесь состоит в том, что этому нужен экземпляр, даже если для дополнительного метода только нужен тип MyType. Таким образом, если нет никакого экземпляра, это нужно назвать как это:

string displayName = BlahBlahUtility.GetDisplayName((MyTpe x) => x.Property);

Который больше не так хорош.

Существует ли способ записать лучший синтаксис для таких случаев?

То, что я на самом деле хочу сделать, является этим (псевдо язык):

string displayName = MyType.Property.GetDisplayName()

Который, конечно, не работает с C#.

Но что относительно чего-то вроде этого:

string displayName = ((MyType x) => x.Property).GetDisplayName();

Это также не возможно (после того, как лямбда, точка не будет принята).

Какие-либо идеи?


Править:

Мой "любимый синтаксис" MyType.Property.GetDisplayName() кажется, вводит в заблуждение. Я не говорю о статических свойствах здесь. Я знаю, что этот синтаксис не будет возможен. Я просто попытался показать на псевдо языке, какая информация необходима. Это было бы идеально, каждый дополнительный материал является просто синтаксическими издержками. Любой рабочий синтаксис, который является близко к этому, был бы большим.

Я не хочу писать определенный дополнительный метод. Я хочу легкое, читаемое и время компиляции безопасный синтаксис, используя любую функцию языка.

6
задан Stefan Steinegger 18 January 2010 в 07:55
поделиться

6 ответов

Взгляна на Express и , отражающих классы в Sokad Sharied Charied . Думаю, они могут помочь с тем, что вы пытаетесь сделать. Читайте больше здесь:

2
ответ дан 17 December 2019 в 18:16
поделиться

Похоже, вы пытаетесь создать статический метод расширения?

DateTime yesterday = DateTime.Yesterday(); // Static extension.

вместо

DateTime yesterday = DateTime.Now.Yesterday(); // Extension on DateTime instance.

, если это то, что вы пытаетесь снять, я не верю Возможно в текущей версии C #.

0
ответ дан 17 December 2019 в 18:16
поделиться

Если вы воспользуетесь своими свойствами, вы можете сделать расширение в интерфейсе вместо этого:

namespace Linq1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyType o = new MyType();
            o.Property.GetDisplayName();
        }
    }

    public class MyType
    {
        public IDisplayableProperty Property { get; set; }
    }

    public interface IDisplayableProperty 
    {
        string GetText();
    }

    public class MyProperty1 : IDisplayableProperty 
    {
        public string GetText() { return "MyProperty2"; }
    }

    public class MyProperty2 : IDisplayableProperty 
    {
        public string GetText() { return "MyProperty2"; }
    }

    public static class Extensions
    {
        public static string GetDisplayName(this IDisplayableProperty o)
        {
            return o.GetText();
        }
    }
}
0
ответ дан 17 December 2019 в 18:16
поделиться

Похоже, вы слишком плотно интегрируете слои. Обычно в этом типе ситуации я бы позволил презентационному слою решить реализацию getDisplayname () вместо того, чтобы сделать его расширением самого свойства. Вы можете создать интерфейс под названием MyTypeedisPlayer или что-то, что вам нравится, и пусть будет несколько реализаций, не ограничивая вас к одной реализации дисплея.

0
ответ дан 17 December 2019 в 18:16
поделиться

Выпуск вот в том, что нельзя получить ссылку на нестатические методы через экземпляр mytype. [Участник]. Это можно увидеть только через ссылку на экземпляр типа. Вы также не можете создать метод расширения в верхней части декларации типа, только на экземпляре типа - то есть сам метод расширения должен быть определен с использованием экземпляра типа (это t x).

Однако можно определить, как это выражение, чтобы получить ссылку на статические элементы: ((Mytype x) => mytype.property)

можно сделать что-то похожее на string displaynamename = ((mytype x) => x.property) .getdisplayname (); Первый вопрос гарантирует, что компилятор относится к вашему (X => X.Property) как выражение, а не действие / функция и т. Д. Для этого может потребоваться сделать это:

string displayName = ((Expression<Func<PropertyType>>)((MyType x) => x.Property).GetDisplayName();

Метод расширения, потом должен быть определен следующим образом:

public static string GetDisplayName<T>(this Expression<Func<T>> expression)

Возможно, вам также необходимо определить метод расширения на вершине . Выражение <действие >> > Если ваши члены также являются методами.

Вы можете сделать точку после выражения - это где метод компиляции будет находиться.

Прилагается:

Я думаю, что статический призыв к методу расширения в случаях, что у человека нет экземпляра типа, которому нужно делать «Отражение», чтобы определить имя члена, будет самым чистым синтаксисом Таким образом, вы все равно можете использовать метод расширения при использовании экземпляра типа и отступить к определению статического вызова => myextensionCass.getdisplayName (typeofx x => typeofx.staticmember или x.property/member ) когда у кого нет экземпляра

0
ответ дан 17 December 2019 в 18:16
поделиться

Из вашего комментария: «Мне нужен простой и безопасный во время компиляции синтаксис для получения информации о членах».

Это очень часто запрашиваемая функция, которая обсуждалась на собраниях команды C # около десяти лет, но никогда не имела достаточно высокого приоритета для включения.

Это сообщение в блоге объясняет, почему:

http://blogs.msdn.com/ericlippert/archive/2009/05/21/in-foof-we-trust-a-dialogue.aspx

Итак, для теперь вы просто будете бороться с отсутствующей функцией. Может быть, вы могли бы опубликовать больше информации о вашей более широкой проблеме и посмотреть, могут ли люди предложить другие подходы.

Обновление

Без дополнительной информации о вашей проблеме это всего лишь предположения. Но если у вас есть свойство, которое представляет значение, но также несет дополнительную «мета» информацию, вы всегда можете представить это как новый тип и использовать шаг «инъекции», чтобы все настроить.

Вот предлагаемый абстрактный интерфейс для такого «метасвойства»:

public interface IMetaProperty<TValue>
{
    TValue Value { get; set; }

    string DisplayName { get; }

    event Action<TValue, TValue> ValueChanged;
}

Значение свойства - это просто еще одно подсвойство, тип которого определяется пользователем.

Я добавил отображаемое имя, а также в качестве бонуса у вас есть событие, которое запускается при изменении значения (так что вы получаете «наблюдаемость» бесплатно).

Чтобы иметь такие свойства в классе, вы должны объявить его следующим образом:

public class SomeClass
{
    public IMetaProperty<string> FirstName { get; private set; }
    public IMetaProperty<string> LastName { get; private set; }
    public IMetaProperty<int> Age { get; private set; }

    public SomeClass() { MetaProperty.Inject(this); }
}

Обратите внимание на то, что установщики свойств являются частными. Это предотвращает случайную установку самого свойства вместо установки вложенного свойства Value.

Это означает, что класс должен настроить эти свойства так, чтобы они не были просто null .Для этого он вызывает волшебный метод Inject , который может работать с любым классом:

public static class MetaProperty
{
    // Make it convenient for us to fill in the meta information
    private interface IMetaPropertyInit
    {
        string DisplayName { get; set; }
    }

    // Implementation of a meta-property
    private class MetaPropertyImpl<TValue> : IMetaProperty<TValue>, 
                                             IMetaPropertyInit
    {
        private TValue _value;

        public TValue Value
        {
            get { return _value; }
            set
            {
                var old = _value;
                _value = value;
                ValueChanged(old, _value);
            }
        }

        public string DisplayName { get; set; }

        public event Action<TValue, TValue> ValueChanged = delegate { };
    }

    public static void Inject(object target)
    {
        // for each meta property...
        foreach (var property in target.GetType().GetProperties()
            .Where(p => p.PropertyType.IsGenericType && 
                        p.PropertyType.GetGenericTypeDefinition() 
                            == typeof(IMetaProperty<>)))
        {
            // construct an implementation with the correct type
            var impl = (IMetaPropertyInit) 
                typeof (MetaPropertyImpl<>).MakeGenericType(
                    property.PropertyType.GetGenericArguments()
                ).GetConstructor(Type.EmptyTypes).Invoke(null);

            // initialize any meta info (could examine attributes...)
            impl.DisplayName = property.Name;

            // set the value
            property.SetValue(target, impl, null);
        }
    }
}

Он просто использует отражение, чтобы найти все слоты IMetaProperty , скрытые в объекте, и заполняет их в с реализацией.

Итак, теперь пользователь SomeClass может сказать:

var sc = new SomeClass
             {
                 FirstName = { Value = "Homer" },
                 LastName = { Value = "Simpson" },
                 Age = { Value = 38 },
             };

Console.WriteLine(sc.FirstName.DisplayName + " = " + sc.FirstName.Value);

sc.Age.ValueChanged += (from, to) => 
    Console.WriteLine("Age changed from " + from + " to " + to);

sc.Age.Value = 39;

// sc.Age = null; compiler would stop this

Если вы уже используете контейнер IOC, вы можете добиться некоторых из этих целей, не переходя непосредственно к рефлексии.

1
ответ дан 17 December 2019 в 18:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: