我正在尝试创建一个方法,该方法将遍历通用对象列表并替换它们的所有 string
类型的属性,该属性要么是 null
,要么是空的。
如何做到这一点的好方法?
我有这种......外壳......到目前为止:
public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
var properties = typeof(T).GetProperties( -- What BindingFlags? -- );
foreach(var p in properties)
{
foreach(var item in list)
{
if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
p.SetValue(item, replacement, null);
}
}
}
那么,我如何找到一个类型的所有属性:
字符串类型
有公开获得
有公开设置吗?
我做了这个测试课:
class TestSubject
{
public string Public;
private string Private;
public string PublicPublic { get; set; }
public string PublicPrivate { get; private set; }
public string PrivatePublic { private get; set; }
private string PrivatePrivate { get; set; }
}
以下不起作用:
var properties = typeof(TestSubject)
.GetProperties(BindingFlags.Instance|BindingFlags.Public)
.Where(ø => ø.CanRead && ø.CanWrite)
.Where(ø => ø.PropertyType == typeof(string));
如果我打印出我到达那里的那些属性的名称,我会得到:
公共公共公共私人私人公共
换句话说,我得到的两个属性太多了。
注意:这可能会以更好的方式完成......使用嵌套的 foreach 和反射等等......但是如果您有任何好的替代想法,请告诉我,因为我想学习!
你的代码重写了。不使用 LINQ 也不使用 var。
public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo p in properties)
{
// Only work with strings
if (p.PropertyType != typeof(string)) { continue; }
// If not writable then cannot null it; if not readable then cannot check it's value
if (!p.CanWrite || !p.CanRead) { continue; }
MethodInfo mget = p.GetGetMethod(false);
MethodInfo mset = p.GetSetMethod(false);
// Get and set methods have to be public
if (mget == null) { continue; }
if (mset == null) { continue; }
foreach (T item in list)
{
if (string.IsNullOrEmpty((string)p.GetValue(item, null)))
{
p.SetValue(item, replacement, null);
}
}
}
}
您将使用 BindingFlags.Public | BindingFlags.Instance
找到这些属性。然后,您需要通过检查 CanWrite 和 CanRead 属性来检查每个 PropertyInfo 实例,以确定它们是否可读和/或可写。
更新:代码示例
PropertyInfo[] props = yourClassInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < props.Length; i++)
{
if (props[i].PropertyType == typeof(string) && props[i].CanWrite)
{
// do your update
}
}
在您更新后,我对其进行了更详细的研究。如果您还检查 GetGetMethod 和 GetSetMethod 返回的 MethodInfo 对象,我认为您将达到目标;
var properties = typeof(TestSubject).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(ø => ø.CanRead && ø.CanWrite)
.Where(ø => ø.PropertyType == typeof(string))
.Where(ø => ø.GetGetMethod(true).IsPublic)
.Where(ø => ø.GetSetMethod(true).IsPublic);
默认情况下,这两个方法只返回公共 getter 和 setter(在这种情况下会冒 NullReferenceException 的风险),但是像上面那样传递 true
会使它们也返回私有的。然后您可以检查 IsPublic
(或 IsPrivate
)属性。
如果您不指定任何绑定标志,您将获得公共的实例属性——这就是您想要的。但随后您将需要检查 PropertyInfo 对象上的 PropertyType 是否为 String 类型。除非您事先知道,否则您还需要检查该属性是否如@Fredrik 指示的那样可读/可写。
using System.Linq;
public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
var properties = typeof(T).GetProperties()
.Where( p => p.PropertyType == typeof(string) );
foreach(var p in properties)
{
foreach(var item in list)
{
if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
p.SetValue(item, replacement, null);
}
}
}
BindingFlags.Public | BindingFlags.Instance 应该这样做
获取设置方法()
我同意其他答案,但我更喜欢重构搜索本身以便使用 Linq 轻松查询,因此查询可能如下:
var asm = Assembly.GetExecutingAssembly();
var properties = (from prop
in asm.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where
prop.PropertyType == typeof (string) &&
prop.CanWrite &&
prop.CanRead
select prop).ToList();
properties.ForEach(p => Debug.WriteLine(p.Name));
我以 Assembly 类型为例,它没有读/写字符串属性,但如果相同的代码搜索只是读取属性,结果将是:
代码库
转义代码库
全名
地点
图像运行时版本
哪些是字符串只读程序集类型属性
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
if (prop.PropertyType == typeof(string))
{
var value = prop.GetValue(t);
if (value != null /* && add your condition if exists */)
{
return /* whatever you want in your method*/;
}
}
}