Динамическое свойство ссылочной модели [дубликат]

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

30
задан Micha Wiedenmann 16 August 2015 в 22:15
поделиться

8 ответов

Прежде всего, вам следует избегать использования этого; C # - строго типизированный язык, поэтому используйте преимущества безопасности и производительности типа, которые сопровождают этот аспект.

Если у вас есть законная причина для получения и установки значения свойства динамически (другими словами, когда тип и / или имя свойства не могут быть определены в коде) Мне нужно использовать отражение.

Наиболее интересным способом было бы следующее:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

Однако вы можете кэшировать объект PropertyInfo, чтобы сделать его более читаемым:

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");
44
ответ дан Cirelli94 20 August 2018 в 07:02
поделиться
  • 1
    Кто-то сказал мне, что C # слишком сильно типизирован. После небольшого размышления я решил, что это было не так уж плохо. – deed02392 23 September 2013 в 14:18
  • 2
    вы можете сэкономить много кода (и меньше ошибок кода = меньше), используя это для сохранения. Используйте его, как ruby, и сделайте таблицу db соответствующей вашим свойствам и сосредоточьтесь на алгоритмах, а не на бесконечном наборе текста (как сильных, так и клавиатурных) – Garr Godfrey 14 August 2015 в 20:16
  • 3
    @ deed02392 Сильно типизированный, это хорошо, но проблема static-typed здесь. – Florian 19 July 2018 в 15:01
  • 4
    @Florian, ты пропустил мою шутку :-) – deed02392 19 July 2018 в 15:30
  • 5
    @ deed02392 Черт, теперь это кажется очевидным! недостаточно отражение перед комментированием. – Florian 19 July 2018 в 21:18

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

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        Type propType = property.PropertyType;
        if (value == null)
        {
            if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
            {
                throw new InvalidCastException();
            }
            else
            {
                property.SetValue(this, null, null);
            }
        }
        else if (value.GetType() == propType)
        {
            property.SetValue(this, value, null);
        }
        else
        {
            TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
            object propValue = typeConverter.ConvertFromString(value.ToString());
            property.SetValue(this, propValue, null);
        }
    }
}

Функция SetValue () выдает ошибку, если преобразование не работает.

4
ответ дан Ken Mc 20 August 2018 в 07:02
поделиться

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

С другой стороны, если вам нужно поддерживать список пользовательских свойств, то вы не можете использовать свойства C #. Вам нужно сделать вид, что вы Dictionary, или вам нужно выставить свойство, которое ведет себя как Dictionary. Ниже приведен пример того, как вы можете создать класс Account для пользовательских свойств:

public class Account
{
    Dictionary<string, object> properties;
    public object this[string propertyName]
    {
        get
        {
            if (properties.ContainsKey[propertyName])
                return properties[propertyName];
            else
                return null;
        }
        set
        {
            properties[propertyName] = value;
        }
    }
}
1
ответ дан Paul Williams 20 August 2018 в 07:02
поделиться

Если вы используете .Net 4, теперь можете использовать динамическое ключевое слово.

dynamic foo = account;
foo.Reference = "124ds4EE2s";
3
ответ дан Rob Sedgwick 20 August 2018 в 07:02
поделиться

Вам нужно использовать Reflection:

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

Обратите внимание, что это будет очень медленно.

1
ответ дан SLaks 20 August 2018 в 07:02
поделиться

Я лично предпочитаю работать с методами расширения, вот мой код:

public static class ReflectionExtensions
{
    public static void SetPropertyValue(this object Target,
        string PropertyName,
        object NewValue)
    {
        if (Target == null) return; //or throw exception

        System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);

        if (prop == null) return; //or throw exception

        object value = prop.GetValue(Target, null);

        prop.SetValue(Target, NewValue, null);
    }
}
1
ответ дан Stefan Michev 20 August 2018 в 07:02
поделиться

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

public object this[string propertyName]
{
    get
    {
        if(propertyName == "Reference")
            return this.Reference;
        else
            return null;
    }
    set
    {
        if(propertyName == "Reference")
            this.Reference = value;
        else
            // do error case here            
    }
}

Обратите внимание, что при этом вы теряете безопасность типа.

4
ответ дан Stephan 20 August 2018 в 07:02
поделиться

Вы можете попробовать комбинировать индекс с отражением ...

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        property.SetValue(this,value, null);
    }
}
24
ответ дан Will Bickford 20 August 2018 в 07:02
поделиться
  • 1
    Хорошая работа. Это мне очень помогло – sudhAnsu63 20 December 2012 в 14:44
  • 2
    +1 Работает и для меня. Обратите внимание, что вам нужно обработать свойство, возможно, равное нулю. – Will Bickford 22 March 2013 в 23:54
Другие вопросы по тегам:

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