我需要调用SetSettings()
,并使用splitSettings
中的3个元素,将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
实例说:
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);
}
}
}
EDIT用int, bool, double和string测试它,它工作了,还添加了一个检查,以确保该属性存在并抛出它不存在的异常(可能想要改变异常类型)
EDIT 2:临时解决方案,将添加更多的类型名转换方法,或者如果有人可以建议一个更动态的方式来转换它(如果不是,那么我认为你将不得不知道所有将使用的类型)?
EDIT3从另一个问题的答案(克里斯泰勒)偷了转换方法,谢谢:-)
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,但不能完全确定它是否会正确转换所有类型。
正如其他人提到的,您应该考虑将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; }
}
}
也许你应该将你的可设置属性标记为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];
}
}