Проверить, существует ли свойство в классе

83

Я пытаюсь узнать, существует ли свойство в классе, я пробовал это:

public static bool HasProperty(this object obj, string propertyName)
{
    return obj.GetType().GetProperty(propertyName) != null;
}

Не понимаю, почему не проходит первый тестовый метод?

[TestMethod]
public void Test_HasProperty_True()
{
    var res = typeof(MyClass).HasProperty("Label");
    Assert.IsTrue(res);
}

[TestMethod]
public void Test_HasProperty_False()
{
    var res = typeof(MyClass).HasProperty("Lab");
    Assert.IsFalse(res);
}
Крис-I
источник
4
Не могли бы вы опубликовать соответствующий код MyClass?
nattyddubbs

Ответы:

128

Ваш метод выглядит так:

public static bool HasProperty(this object obj, string propertyName)
{
    return obj.GetType().GetProperty(propertyName) != null;
}

Это добавляет расширение objectк базовому классу всего . Когда вы вызываете это расширение, вы передаете ему Type:

var res = typeof(MyClass).HasProperty("Label");

Ваш метод ожидает экземпляр класса, а не Type. В противном случае вы, по сути, делаете

typeof(MyClass) - this gives an instanceof `System.Type`. 

потом

type.GetType() - this gives `System.Type`
Getproperty('xxx') - whatever you provide as xxx is unlikely to be on `System.Type`

Как правильно указывает @PeterRitchie, на этом этапе ваш код ищет свойство LabelнаSystem.Type . Этого свойства не существует.

Решение либо

a) Предоставьте расширению экземпляр MyClass:

var myInstance = new MyClass()
myInstance.HasProperty("Label")

б) Наденьте удлинитель System.Type

public static bool HasProperty(this Type obj, string propertyName)
{
    return obj.GetProperty(propertyName) != null;
}

и

typeof(MyClass).HasProperty("Label");
Jamiec
источник
2
т.е. ваш код ищет `Type.Label , not MyClass.Label`.
Питер Ричи
Как бы это поместить в расширение System.Type, где бы это можно было найти /. Куда это нужно выполнить в коде?
Demodave
1
@Demodave - методы расширения находятся в публичном статическом классе. Дополнительную информацию см. Здесь: msdn.microsoft.com/en-GB/library/bb383977.aspx
Jamiec,
Если вы получили такую ​​ошибку: «Тип не содержит определения для GetProperty», прочтите это: stackoverflow.com/questions/7858469/…
Тадей
27

Это отвечает на другой вопрос:

Если вы пытаетесь выяснить, имеет ли ОБЪЕКТ (не класс) свойство,

OBJECT.GetType().GetProperty("PROPERTY") != null

возвращает истину, если (но не только если) свойство существует.

В моем случае я был в частичном представлении ASP.NET MVC и хотел отрендерить что-нибудь, если либо свойство не существует, либо свойство (логическое) было истинным.

@if ((Model.GetType().GetProperty("AddTimeoffBlackouts") == null) ||
        Model.AddTimeoffBlackouts)

помог мне здесь.

Изменить: в настоящее время, вероятно, разумно использовать nameofоператор вместо строкового имени свойства.

Стаху
источник
Что касается использования nameofоператора, будет ли он работать (без исключения), чтобы получить имя свойства, которое может не существовать? Поскольку исходный вопрос предполагал, что мы не знаем, существует ли это свойство?
Зои
Почему бы вам не попробовать, а затем отредактировать мой ответ, чтобы уточнить?
Stachu
2

Есть 2 возможности.

У тебя действительно нет Labelсобственности.

Вам нужно вызвать соответствующую перегрузку GetProperty и передать правильные флаги привязки, напримерBindingFlags.Public | BindingFlags.Instance

Если ваша собственность не является общедоступной, вам нужно будет использовать BindingFlags.NonPublic или другую комбинацию флагов, которая соответствует вашему варианту использования. Прочтите упомянутую документацию по API, чтобы узнать подробности.

РЕДАКТИРОВАТЬ:

Опа, только заметил , что вы звоните GetPropertyна typeof(MyClass). typeof(MyClass)у Typeкоторого точно нет Labelсобственности.

Здеслав Войкович
источник
По умолчанию используются флаги привязки: Instance|Public|Staticiirc.
LukeH
@LukeH, я не был уверен, поэтому написал «правильно» и добавил «например» :) возможно, Labelэто частная собственность.
Здеслав Войкович
1

Я получил эту ошибку: «Тип не содержит определения для GetProperty» при связывании принятого ответа.

Вот что у меня получилось:

using System.Reflection;

if (productModel.GetType().GetTypeInfo().GetDeclaredProperty(propertyName) != null)
{

}
Тадей
источник
0

Если вы связываетесь, как я:

<%# Container.DataItem.GetType().GetProperty("Property1") != null ? DataBinder.Eval(Container.DataItem, "Property1") : DataBinder.Eval(Container.DataItem, "Property2")  %>
Бен
источник
0

Я не уверен в контексте того, почему это было необходимо, так что это может не дать вам достаточно информации, но вот что я смог сделать:

if(typeof(ModelName).GetProperty("Name of Property") != null)
{
//whatevver you were wanting to do.
}

В моем случае я просматриваю свойства из отправки формы, а также имею значения по умолчанию для использования, если запись оставлена ​​пустой - поэтому мне нужно было знать, было ли значение для использования - я поставил все свои значения по умолчанию в модели с Default, поэтому все, что мне нужно было сделать, это проверить, есть ли свойство, которое начинается с этого.

C Gil
источник