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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/824802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:07:14  来源:igfitidea点击:

C#: How to get all public (both get and set) string properties of a type

c#reflection

提问by Svish

I am trying to make a method that will go through a list of generic objects and replace all their properties of type stringwhich is either nullor empty with a replacement.

我正在尝试创建一个方法,该方法将遍历通用对象列表,并用替换替换它们的所有类型的属性,这些属性string要么是要么是null空的。

How is a good way to do this?

这样做的好方法是什么?

I have this kind of... shell... so far:

我有这种......外壳......到目前为止:

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

So, how do I find all the properties of a type that are:

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

  • Of type string
  • Has public get
  • Has public set

    ?

  • 类型 string
  • 有公开 get
  • 有公开 set

    ?



I made this test class:

我做了这个测试类:

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

The following does not work:

以下不起作用:

var properties = typeof(TestSubject)
        .GetProperties(BindingFlags.Instance|BindingFlags.Public)
        .Where(? => ?.CanRead && ?.CanWrite)
        .Where(? => ?.PropertyType == typeof(string));

If I print out the Name of those properties I get there, I get:

如果我打印出我到达那里的那些属性的名称,我会得到:

PublicPublic PublicPrivate PrivatePublic

公共公共公共私人私人公共

In other words, I get two properties too much.

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



Note: This could probably be done in a better way... using nested foreach and reflection and all here... but if you have any great alternative ideas, please let me know cause I want to learn!

注意:这可能会以更好的方式完成……使用嵌套的 foreach 和反射以及所有这些……但是如果您有任何好的替代想法,请告诉我,因为我想学习!

采纳答案by Colin Burnett

Your code rewritten. Does not use LINQ nor var.

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

回答by ba__friend

BindingFlags.Public | BindingFlags.Instance should do it

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

GetSetMethod()

获取设置方法()

回答by Fredrik M?rk

You will find the properties as such with BindingFlags.Public | BindingFlags.Instance. Then you will need to examine each PropertyInfo instance by checking the CanWrite and CanRead properties, in order to find out whether they are are readable and/or writeable.

您将通过BindingFlags.Public | BindingFlags.Instance. 然后您需要通过检查 CanWrite 和 CanRead 属性来检查每个 PropertyInfo 实例,以确定它们是否可读和/或可写。

Update: code example

更新:代码示例

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
    }
}


I looked into it more in detail after your update. If you also examine the MethodInfo objects returned by GetGetMethod and GetSetMethod you will hit the target, I think;

在您更新后,我更详细地研究了它。如果您还检查 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);

By default these two methods return only public getters and setters (risking a NullReferenceException in a case like this), but passing trueas above makes them also return private ones. Then you can examine the IsPublic(or IsPrivate) properties.

默认情况下,这两个方法仅返回公共 getter 和 setter(在这种情况下冒 NullReferenceException 的风险),但true如上传递使它们也返回私有的。然后您可以检查IsPublic(或IsPrivate)属性。

回答by Ron Klein

I suggest a different approach: AOP.
You can intercept the setter and set the desired value to a valid one. With PostSharpit's quite easy.

我建议采用不同的方法:AOP
您可以拦截 setter 并将所需值设置为有效值。使用PostSharp非常简单。

回答by tvanfosson

If you don't specify any binding flags you will get the public, instance properties -- which is what you want. But then you will need to check if the PropertyType on the PropertyInfo object is of type String. Unless you know in advance, you'll also need to check whether the property is readable/writable as @Fredrik indicates.

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

回答by Hoghweed

I agree with other answers, but I prefer to refactor the search itself to be easly queried with Linq, so the query could be as follow:

我同意其他答案,但我更喜欢重构搜索本身,以便使用 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));

I took for my example the Assembly type, which hasn't read/write string properties, but if the same code search for just read properties, the result will be:

我以程序集类型为例,它没有读/写字符串属性,但如果相同的代码只搜索读取属性,结果将是:

  • CodeBase
  • EscapedCodeBase
  • FullName
  • Location
  • ImageRuntimeVersion
  • 代码库
  • 转义代码库
  • 全名
  • 地点
  • 图像运行时版本

Which are the stringread-onlyAssembly type properties

哪些是字符串只读程序集类型属性

回答by jeffery

http://jefferytay.wordpress.com/2010/05/03/simple-and-useful-tostring/

http://jefferytay.wordpress.com/2010/05/03/simple-and-useful-tostring/

for a tostring override method which allows you to get all the properties of the class

对于允许您获取类的所有属性的 tostring 覆盖方法