WPF - ComboBox и DisplayMemberPath [дубликат]

Консенсус заключается в использовании словаря для этого - см. другие ответы. Это хорошая идея для большинства случаев, однако есть много аспектов, связанных с этим:

  • вы сами будете нести ответственность за этот словарь, включая сбор мусора (из переменных in-dict) и т. Д. .
  • нет никакой локальности или глобальности для переменных переменных, это зависит от глобальности словаря
  • , если вы хотите переименовать имя переменной, вам придется сделать это вручную
  • однако вы гораздо более гибкие, например вы можете решить перезаписать существующие переменные или ... ... выбрать реализацию константных переменных для создания исключения при перезаписи для разных типов и т. д.

Тем не менее, я реализовал variable variables manager -класс, который предоставляет некоторые из вышеперечисленных идей. Он работает для python 2 и 3.

Вы использовали бы класс следующим образом:

from variableVariablesManager import VariableVariablesManager

myVars = VariableVariablesManager()
myVars['test'] = 25
print(myVars['test'])

# define a const variable
myVars.defineConstVariable('myconst', 13)
try:
    myVars['myconst'] = 14 # <- this raises an error, since 'myconst' must not be changed
    print("not allowed")
except AttributeError as e:
    pass

# rename a variable
myVars.renameVariable('myconst', 'myconstOther')

# preserve locality
def testLocalVar():
    myVars = VariableVariablesManager()
    myVars['test'] = 13
    print("inside function myVars['test']:", myVars['test'])
testLocalVar()
print("outside function myVars['test']:", myVars['test'])

# define a global variable
myVars.defineGlobalVariable('globalVar', 12)
def testGlobalVar():
    myVars = VariableVariablesManager()
    print("inside function myVars['globalVar']:", myVars['globalVar'])
    myVars['globalVar'] = 13
    print("inside function myVars['globalVar'] (having been changed):", myVars['globalVar'])
testGlobalVar()
print("outside function myVars['globalVar']:", myVars['globalVar'])

Если вы хотите разрешить переписывание переменных с помощью только тот же тип:

myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)

16
задан Paul Alexander 9 May 2009 в 11:03
поделиться

2 ответа

Связывание обычно не работает с полями. Большинство привязок основаны, в частности, на модели ComponentModel PropertyDescriptor, которая (по умолчанию) работает над свойствами. Это дает возможность уведомлений, проверки и т. Д. (Ни одна из которых не работает с полями).

По другим причинам, по которым я могу пойти, открытые поля - плохая идея. Они должны быть свойствами, фактом. Аналогично, изменчивые структуры - очень плохая идея. Не в последнюю очередь это защищает от непредвиденных потерь данных (обычно связанных с изменчивыми структурами). Это должен быть класс:

[DataContract]
public class StatusInfo
{
    [DataMember] public int Total {get;set;}
    [DataMember] public string Authority {get;set;}
}

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

[DataContract]
public struct StatusInfo
{
    [DataMember] public int Total {get;private set;}
    [DataMember] public string Authority {get;private set;}

    public StatusInfo(int total, string authority) : this() {
        Total = total;
        Authority = authority;
    }
}

Однако я бы сначала спросил, почему это структуры в первую очередь. Редактировать структуру на языках .NET очень редко. Имейте в виду, что прокси-сервер WCF «mex» будет создавать его как класс у потребителя в любом случае (если вы не используете совместное использование сборок).


В ответ на ответ «зачем использовать структуру» ответ ( «unknown (google)»):

Если это ответ на мой вопрос, это неправильно во многих отношениях. Во-первых, типы значений как переменные обычно выделяются (сначала) в стеке. Если они попадают в кучу (например, в массиве / списке), нет большой разницы в накладных расходах от класса - небольшой бит заголовка объекта плюс ссылка. Структуры всегда должны быть маленькими. Что-то с несколькими полями будет чрезмерно крупным и будет либо убивать ваш стек, либо просто вызвать медленность из-за блуждания. Кроме того, структуры должны быть неизменными - если вы действительно не знаете, что делаете.

Практически все, что представляет объект, должно быть бескомпромиссным.

Если вы попадаете в базу данных, скорость struct vs class является не-проблемой по сравнению с выходом из процесса и, вероятно, по сети. Даже если это немного медленнее, это ничего не значит по сравнению с тем, что нужно сделать правильно - т.е. рассматривать объекты как объекты.

Как некоторые метрики над объектами 1M:

struct/field: 50ms
class/property: 229ms

на основе следующего (разница в скорости в распределении объектов, а не в поле vs). Так что примерно в 5 раз медленнее, но все же очень, очень быстро. Поскольку это не будет вашим узким местом, преждевременно не оптимизируйте это!

using System;
using System.Collections.Generic;
using System.Diagnostics;
struct MyStruct
{
    public int Id;
    public string Name;
    public DateTime DateOfBirth;
    public string Comment;
}
class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Comment { get; set; }
}
static class Program
{
    static void Main()
    {
        DateTime dob = DateTime.Today;
        const int SIZE = 1000000;
        Stopwatch watch = Stopwatch.StartNew();
        List<MyStruct> s = new List<MyStruct>(SIZE);
        for (int i = 0; i < SIZE; i++)
        {
            s.Add(new MyStruct { Comment = "abc", DateOfBirth = dob,
                     Id = 123, Name = "def" });
        }
        watch.Stop();
        Console.WriteLine("struct/field: "
                  + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        List<MyClass> c = new List<MyClass>(SIZE);
        for (int i = 0; i < SIZE; i++)
        {
            c.Add(new MyClass { Comment = "abc", DateOfBirth = dob,
                     Id = 123, Name = "def" });
        }
        watch.Stop();
        Console.WriteLine("class/property: "
                   + watch.ElapsedMilliseconds + "ms");
        Console.ReadLine();
    }
}
23
ответ дан Marc Gravell 23 August 2018 в 00:28
поделиться
  • 1
    Как программист на C ++ я считаю, что ваши комментарии выше очень трудно понять. Я также, похоже, прихожу к разным выводам. Например, вы говорите: «Так что примерно в 5 раз медленнее, но все же очень, очень быстро». В то время как я вижу это как «Использование структур в 5 раз быстрее, но все же очень, очень медленно». – Daniel Paull 5 July 2012 в 04:12
  • 2
    @ Даниэль вздыхает, здесь мы снова идем, «C ++ быстрее, чем все, когда-либо, и должен использоваться всегда». (вздох). В широком спектре применений нет заметной разницы, кроме одного, что значительно легче получить право. – Marc Gravell♦ 5 July 2012 в 07:33
  • 3
    Я никогда не говорил, что C ++ быстрее! Заключая такие, вы указали, что у вас есть серьезные предубеждения (или, может быть, неправильные представления). «В широком спектре применений нет заметной разницы, кроме одного, что значительно легче получить право». - поэтому мы согласны, хотя C ++ может быть быстрее, это не важно - однако C ++ упрощает его правильное, и это важно. Или, может быть, я просто неправильно истолковал то, что вы сказали, чтобы поддержать мой аргумент ... В самом деле. – Daniel Paull 9 July 2012 в 05:41
  • 4
    @ Даниэль, может быть, я неправильно понял ваш смысл & quot; как программист на C ++ ... но все же очень, очень медленный & quot; – Marc Gravell♦ 9 July 2012 в 06:14
  • 5
    Вероятно, ваш тест производительности слишком короткий, чтобы правильно измерить накладные расходы GC. Попробуйте эту модификацию ваших тестов: pastebin.com/Ajkj0hdm - теперь классы на 12 раз медленнее, потому что 80% времени проводится в GC. Теперь сверните РАЗМЕР до 10M и посмотрите «частные байты»: 200 МБ для структур, взлетев до 1 ГБ для классов. – Roman Starkov 23 August 2012 в 11:09

Я могу только догадываться, почему они поддерживают только свойства: возможно, потому, что, как представляется, универсальное соглашение в платформе .NET никогда не выставляет изменчивые поля (, вероятно, для защиты бинарной совместимости ), и они каким-то образом ожидал, что все программисты будут следовать одному и тому же соглашению.

Кроме того, хотя поля и свойства доступны с одним и тем же синтаксисом, привязка данных использует отражение, и (поэтому я слышал) отражение должно использоваться по-разному для полей доступа чем для доступа к свойствам.

0
ответ дан Qwertie 23 August 2018 в 00:28
поделиться
Другие вопросы по тегам:

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