Bir özelliği dize değeriyle yansıtarak ayarlama


312

Nesnenin bir özelliğini Yansıma türüyle, tip değeri olan bir değer ayarlamak istiyorum string. Dolayısıyla, örneğin, bir olduğunu varsayalım Shipbir özelliğiyle, sınıf Latitudebir olduğunu double.

İşte yapmak istediklerim:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);

Olduğu gibi, bu bir atar ArgumentException:

'System.String' türündeki nesne 'System.Double' türüne dönüştürülemiyor.

Değeri temel alarak uygun türe nasıl dönüştürebilirim propertyInfo?


1
Size soru: Bu özel bir ORM çözümünün bir parçası mı?
user3308043

Yanıtlar:


527

Kullanabilirsiniz Convert.ChangeType()- Sunum IConvertiblebiçimlerini değiştirmek için herhangi bir türdeki çalışma zamanı bilgilerini kullanmanıza olanak tanır . Bununla birlikte, tüm dönüşümler mümkün değildir ve olmayan türlerden dönüşümleri desteklemek istiyorsanız özel durum mantığı yazmanız gerekebilir IConvertible.

İlgili kod (istisna işleme veya özel durum mantığı olmadan):

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

Aşağıdaki @AKaraca cevabını inceleyin. Hem bu hem de aşağıdaki hızlı ve gevşek ama ortak tipler için işi yapıyor.
Aaron Hudon

Bir TryChangeTypeveya var CanChangeTypemı?
Shimmy Weitzhandler

34

Diğerlerinin söylediği gibi, kullanmak istersiniz Convert.ChangeType:

propertyInfo.SetValue(ship,
    Convert.ChangeType(value, propertyInfo.PropertyType),
    null);

Aslında, tüm ConvertSınıf'a bakmanızı tavsiye ederim .

Bu sınıf ve diğer birçok yararlı sınıf, SystemAd Alanı'nın bir parçasıdır . Hangi özellikleri kaçırdığımı görmek için her yıl bu ad alanını taramanın yararlı olduğunu düşünüyorum. Bir şans ver!


1
OP muhtemelen bir dizeden bariz bir dönüşüme sahip herhangi bir tipte bir özellik ayarlamak için genel bir cevap ister.
Daniel Earwicker

İyi bir nokta. Düzenleyeceğim ve gerçek yanıtlayıcıları göstereceğim ya da birisi ad alanının geri kalanıyla ilgili söylediklerimi ekleyecekse benimkini sileceğim.
John Saunders

19

Bir çok insanın tavsiye Convert.ChangeTypeettiğini fark ettim - Bu bazı durumlar için işe yarıyor, ancak nullabletürleri dahil etmeye başlar başlamaz almaya başlayacaksınız InvalidCastExceptions:

http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

Birkaç yıl önce bununla başa çıkmak için bir sarıcı yazıldı ancak bu da mükemmel değil.

http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx


13

LBushkin'in cevabını denedim ve harika çalıştı, ancak boş değerler ve boş değerler için işe yaramaz. Bu yüzden bunu şu şekilde değiştirdim:

propertyName= "Latitude";
PropertyInfo propertyInfo = ship.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
     Type t = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
     object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
     propertyInfo.SetValue(ship, safeValue, null);
}

Bu davayla tanıştığımda teşekkür etmek zorundayım ve bu tek çözüm. teşekkürler ~!
Franva

11

Bir tip dönüştürücü kullanabilirsiniz (hata kontrolü yok):

Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);

Kodun düzenlenmesi açısından, aşağıdaki gibi kodla sonuçlanacak bir tür mixin oluşturabilirsiniz:

Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");

Bu, şu kodla gerçekleştirilebilir:

public interface MPropertyAsStringSettable { }
public static class PropertyAsStringSettable {
  public static void SetPropertyAsString(
    this MPropertyAsStringSettable self, string propertyName, string value) {
    var property = TypeDescriptor.GetProperties(self)[propertyName];
    var convertedValue = property.Converter.ConvertFrom(value);
    property.SetValue(self, convertedValue);
  }
}

public class Ship : MPropertyAsStringSettable {
  public double Latitude { get; set; }
  // ...
}

MPropertyAsStringSettable birçok farklı sınıf için tekrar kullanılabilir.

Özelliklerinize veya sınıflarınıza eklemek için kendi özel tür dönüştürücülerinizi de oluşturabilirsiniz :

public class Ship : MPropertyAsStringSettable {
  public Latitude Latitude { get; set; }
  // ...
}

[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }

İşaretleyici arayüzünü sadece kullanmak yerine eklemenizin özel bir nedeni var mı object?
Groo

1
Evet, işaretçi arabirimi, uzantı yöntemlerini eklemek için bir yer tutucu görevi görür. Kullanmak object, genel olarak istenmeyen tüm sınıflara genişletme yöntemlerini ekleyecektir.
Jordão

6

Muhtemelen Convert.ChangeTypeyöntemi arıyorsunuz . Örneğin:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

5

Convert.ChangeTypeDönüştürme türünü kullanma ve alma PropertyInfo.PropertyType.

propertyInfo.SetValue( ship,
                       Convert.ChangeType( value, propertyInfo.PropertyType ),
                       null );

4

Bunu genel bir cevapla cevaplayacağım. Genellikle bu cevaplar kılavuzlarla çalışmaz. İşte kılavuzlarla birlikte çalışan bir sürüm.

var stringVal="6e3ba183-89d9-e611-80c2-00155dcfb231"; // guid value as string to set
var prop = obj.GetType().GetProperty("FooGuidProperty"); // property to be setted
var propType = prop.PropertyType;

// var will be type of guid here
var valWithRealType = TypeDescriptor.GetConverter(propType).ConvertFrom(stringVal); 

1
Bu kabul edilen cevap olmalı. Ayrıca <3 GUID'leri ile de çalışır. Teşekkürler, Ali (kızımın takma adı)
Cătălin Rădoi

3

Ya da deneyebilirsiniz:

propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

//But this will cause problems if your string value IsNullOrEmplty...

2

Metro uygulaması yazıyorsanız, başka bir kod kullanmalısınız:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));

Not:

ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");

onun yerine

ship.GetType().GetProperty("Latitude");

0

Aşağıdaki kodu kullanmak sorununuzu çözmelidir:

item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));

-9

Reflection ile oynamak mı istiyorsunuz yoksa bir üretim yazılımı parçası mı oluşturmak istiyorsunuz? Neden bir mülk ayarlamak için yansıma kullandığınızı sorgulayacağım.

Double new_latitude;

Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;

1
İnsanların ne yapmaya çalıştıklarına saygı göstermelisiniz. Downvoted. (Başlangıç GenericProgramming.exe:ReflectionBenefits())
Петър Петров
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.