#c# #reflection #c#-4.0 #reference-type
#c# #отражение #c #-4.0 #ссылочный тип
Вопрос:
Мне нужно вызвать SetSettings()
и, используя 3 элемента в splitSettings
, установить EncodeAudio
значение False
. Как бы я это сделал? Преобразовать свойство объекта в имя того, кто у меня есть в строке. Я понимаю, что мог бы использовать оператор switch для всех моих настроек, но должен быть более динамичный способ сделать это.
namespace SettingsLib
{
public class Settings
{
public Boolean EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
// Need to set EncodeAudio to False in SettingsLib.Settings
}
}
Да, у меня есть экземпляр настроек
Скажем:
Settings settingManager = new Settings();
Я пытаюсь динамически установить EncodeAudo в False, используя элементы splitSettings
settingManager.EncodeAudio = False;
Благодаря помощи TBohnen.jnr
Я пришел к этому ответу:
public void setProperty(object containingObject, string propertyName, object newValue)
{
foreach (PropertyInfo p in containingObject.GetType().GetProperties())
{
if (p.Name == propertyName)
{
p.SetValue(containingObject, Convert.ChangeType(newValue, p.PropertyType), null);
}
}
}
Комментарии:
1. У вас где-нибудь есть экземпляр вашего объекта Settings? Нет смысла пытаться сделать это, если вы этого не сделаете. Динамическая попытка создать экземпляр этого объекта по имени была бы выполнима. Это то, что вы пытаетесь сделать?
2. Или, может быть, метод EncodeAudio должен быть статическим?
3. Даже если оно статическое, как мне определить, какое свойство использовать, исходя из его имени в виде строки?
Ответ №1:
EDIT Протестировал это с помощью int, bool, double и string, и это сработало, также добавил проверку, чтобы убедиться, что свойство существует, и выдает исключение, которого нет (возможно, потребуется изменить тип исключения)
ПРАВКА 2: Временное решение, добавит ли больше имен типов в метод convert или, альтернативно, если кто-нибудь может предложить более динамичный способ его приведения (если нет, то я предполагаю, что вам нужно будет знать все типы, которые будут использоваться)?
EDIT3 Украл метод convert из другого ответа на вопрос (Крис Тейлор), спасибо 🙂
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
var type = containingObject.GetType().GetProperties().First(c => c.Name == propertyName).PropertyType;
object val = Convert(type,(string)newValue);
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { val });
}
else
{
throw new KeyNotFoundException("The property: " propertyName " was not found in: " containingObject.GetType().Name);
}
}
public object convert(System.Type type, string value)
{
return Convert.ChangeType(value, type);
}
Взято из http://www.haslo.ch/blog/setproperty-and-getproperty-with-c-reflection /
Было интересно посмотреть, работает ли это, создайте быстрый тест:
class testSettings
{
public bool SetBool { get; set; }
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { newValue });
}
else
{
throw new KeyNotFoundException("The property: " propertyName " was not found in: " containingObject.GetType().Name);
}
}
}
static void Main(string[] args)
{
testSettings ts = new testSettings();
ts.SetBool = false;
ts.setProperty(ts, "SetBool", true);
Console.WriteLine(ts.SetBool.ToString());
Console.Read();
}
Вывод true, хотя не совсем уверен, что он правильно преобразует все типы.
Комментарии:
1. Это на правильном пути, но все еще не завершено, вы передаете bool true, я передаю «true», который не работает. ts.setProperty(ts, «setBool», «true»); сбой с System.missingmethod Exception. Теперь, я думаю, мне нужно преобразовать строку в значения в правильный тип.
2. да, я работал над этим и пришел к тому же решению: public void setProperty(объект, содержащий Object, строковое propertyName, object newValue) { foreach (PropertyInfo p в containingObject. GetType().GetProperties()) { если (p.Name == propertyName) { p.setValue(содержащий объект, преобразовать. Тип изменения(newValue, p.PropertyType), null); } } }
Ответ №2:
Как упоминали другие, вам следует подумать о том, чтобы сделать ваш класс SettingsLib статическим. И вам также может потребоваться обработать преобразование значений из строк в целевые типы. Вот простой пример того, как это будет работать.
namespace Service
{
class Program
{
static void Main(string[] args)
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
SetProperty(splitSettings[0], splitSettings[1], splitSettings[2]);
}
static void SetProperty(string typeName, string propertyName, object value)
{
var type = Type.GetType(typeName);
if (type == null)
{
throw new ArgumentException("Unable to get type", "typeName");
}
var pi = type.GetProperty(propertyName);
if (pi == null)
{
throw new ArgumentException("Unable to find property on type", "propertyName");
}
object propertyValue = value;
if (propertyValue != null)
{
// You might need more elaborate testing here to ensure that you can handle
// all the various types, you might need to special case some types here
// but this will work for the basics.
if (pi.PropertyType != propertyValue.GetType())
{
propertyValue = Convert.ChangeType(propertyValue, pi.PropertyType);
}
}
pi.SetValue(null, propertyValue, null);
}
}
}
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
Комментарии:
1. Тип. Похоже, что GetType (typeName) всегда возвращает null. Даже если настройки класса и свойство являются статическими.
2. Спасибо за преобразование. Тип изменения, это сэкономило бы мне некоторое время в прошлом 🙂
3. @jpiccolo, если GetType(typeName) возвращает null, это означает, что передаваемое вами имя типа не соответствует имени типа, к которому вы пытаетесь получить доступ. Вы можете использовать ILDASM или Reflector, чтобы проверить, что вы используете правильное имя.
Ответ №3:
Возможно, вам следует пометить свои настраиваемые свойства как static
, а затем попытаться установить значения с помощью отражения:
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
dynamic property = Type.GetType(splitSettings[0]).GetProperty(splitSettings[1]);
property = splitSettings[2];
}
}