Почему ListBox.DisplayMember принимает строковое значение?

#c# #properties

#c# #свойства

Вопрос:

В настоящее время я новичок в C #, и большая часть моих знаний исходит из Java и Python. С учетом сказанного, в настоящее время у меня есть следующий код:

 public class Person
{
    public int Person_ID { get; set; }
    public String First_Name { get; set; }
    public String Last_Name { get; set; }
    public String EmailAddress { get; set; }


    public String FullInfo
    {
        get
        {
            // Matthew Arnold (mtthwrnld@gmail.com)
            return $"{First_Name}, {Last_Name}, ({EmailAddress})";
        }
    }

}
  

с помощью используемого здесь свойства «FullInfo»:

 private void button1_Click(object sender, EventArgs e)
{
    //'Results' is a ListBox
    //'people' is a List of type Person

    DataAccess db = new DataAccess();
    people = db.getPeople(lastNameText.Text);

    Results.DataSource = people;
    Results.DisplayMember = "FullInfo";
}
  

Мой вопрос касается этой строки явно: Results.DisplayMember = "FullInfo";

Как это назначение на самом деле работает? Мы устанавливаем DisplayMember в FullInfo свойство, но мы оборачиваем его в String . Почему мы просто не делаем Results.DisplayMember = Person.FullInfo ?

Откуда компилятор знает, что это не какое-либо старое String ? Каковы преимущества доступа к свойству таким образом?

Комментарии:

1. Потому что, когда вы устанавливаете DisplayMember , оно просматривает DataSource для этого свойства объекта… Если вы это сделаете Results.DisplayMember = Person.FullInfo , это не будет представлять экземпляр класса person, скорее это будет указание ему искать свойство с именем Person.FullInfo .

Ответ №1:

Здесь вы имеете дело с отражением. Взгляните на эту функцию:

 public static void GetDisplayName(object anyType, string displayName)
{
    var type = anyType.GetType();

    var displayProperty = type.GetProperty(displayName);
    if (displayProperty != null)
    {
        Console.WriteLine($"DisplayName is {displayProperty.GetValue(anyType)}");
        return;
    }

    var displayFiled = type.GetField(displayName);
    if (displayFiled != null)
    {
        Console.WriteLine($"DisplayName is {displayFiled.GetValue(anyType)}");
        return;
    }

    // can't find displayName
    Console.WriteLine($"DisplayName is {type.Name}");
}
  

Если вы вызываете это как

 var person = new Person
{
    Person_ID = 42,
    First_Name = "First",
    Last_Name = "Last",
    EmailAddress = "name@domain.com"
};

GetDisplayName(person, "FullInfo");
  

Он выведет

DisplayName является первым, последним, (name@domain.com )

Точно так же, как в вашем примере в вопросе, мы передаем "FullInfo" в него только как строку. Но внутренний код ListBox достаточно умен, чтобы использовать эту строку в качестве сопоставления с фактическим значением

Комментарии:

1. Спасибо. Возможно, мне потребуется некоторое время, чтобы полностью охватить отражение, но это прекрасно проясняет мой вопрос.

Ответ №2:

Почему мы просто не создаем результаты.DisplayMember = Person.FullInfo?

Это установило бы значение DisplayMember в строку, которую возвращает FullInfo. Значение DisplayMember должно быть именем свойства, содержащего отображаемое значение.

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

 Results.DataSource = people;
Results.DisplayMember = nameof(person.FullInfo);
  

Комментарии:

1. Стоит отметить, что nameof оператор доступен только начиная с C # 6.0.

Ответ №3:

ListBox использует отражение внутри себя при отображении данных из своего источника данных. В C # отражение — это мощный механизм, с помощью которого вы можете получить доступ к полям i.e объекта, имея только имя поля в виде строки.

Вы можете попробовать отражение со следующим фрагментом:

 var person = new Person{First_Name = "FirstName", Last_Name="LastName", Person_ID=12, EmailAddress="email@email.com"};
var fullInfo = person.GetType().GetProperty("FullInfo").GetValue(person, null);