如何获取类型的所有公共字符串属性(包括 get 和 set)

我试图使一个方法,将通过一个泛型对象的列表,并替换其类型为 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);
}
}
}

那么,我如何找到一个类型的所有属性:

  • 类型为 string

  • 有公共 get

  • 有公共 set


我参加了一个测试班:

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));

如果我打印出这些属性的名称,我得到:

公众人士 PublicPrivate 私营机构

换句话说,我得到的两个属性太多了。


注意 : 这可能可以用一种更好的方式来完成... 使用嵌套的前伸和反射和所有这里... 但是如果你有任何伟大的替代想法,请让我知道,因为我想学习!

97405 次浏览

BindingFlags.Public | BindingFlags.Instance 应该这样做

GetSetMethod ()

您将在 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使它们也返回私有的 getter 和 setter。然后可以检查 IsPublic(或 IsPrivate)属性。

我建议采用一种不同的方法: AOP
您可以拦截 setter 并将所需的值设置为有效值。

如果不指定任何绑定标志,您将获得公共、实例属性——这正是您想要的。但是,您需要检查 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);
}
}
}

您的代码已重写。不使用 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);
}
}
}
}

我同意其他的答案,但我更喜欢重构搜索本身,以便使用 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 类型为例,它没有读/写字符串属性,但是如果同样的代码搜索只读属性,结果将是:

  • 代码库
  • 转义代码库
  • 全名
  • 地点
  • ImageRuntimeVersion

它们是 绳子 只读程序集类型属性

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*/;
}
}
}