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, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Прежде всего, вам следует избегать использования этого; 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");
Я использовал метод отражения от Ричарда, но разработал метод 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 () выдает ошибку, если преобразование не работает.
Я согласен с предыдущими плакатами, что вы, вероятно, должны использовать свойства. Отражение происходит очень медленно по сравнению с прямым доступом к свойствам.
С другой стороны, если вам нужно поддерживать список пользовательских свойств, то вы не можете использовать свойства 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;
}
}
}
Если вы используете .Net 4, теперь можете использовать динамическое ключевое слово.
dynamic foo = account;
foo.Reference = "124ds4EE2s";
Вам нужно использовать Reflection:
PropertyInfo property = typeof(Account).GetProperty("Reference");
property.SetValue(myAccount, "...", null);
Обратите внимание, что это будет очень медленно.
Я лично предпочитаю работать с методами расширения, вот мой код:
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);
}
}
Если это ваши собственные объекты, вы можете предоставить индекс для доступа к полям. Я не рекомендую это, но это позволит вам что угодно.
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
}
}
Обратите внимание, что при этом вы теряете безопасность типа.
Вы можете попробовать комбинировать индекс с отражением ...
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);
}
}