以字符串形式访问对象属性并设置其值

发布于 2024-09-02 11:18:10 字数 493 浏览 7 评论 0原文

我有一个 Account 类的实例。每个帐户对象都有一个所有者、引用等。

我访问帐户属性的一种方法是通过类似的访问器,

account.Reference;

但我希望能够使用动态字符串选择器来访问它,例如:

account["PropertyName"];

就像在 JavaScript 中一样。所以我会有account["Reference"]它将返回值,但我也希望能够在之后分配一个新值,例如:

account["Reference"] = "124ds4EE2s";

我注意到我可以用来

DataBinder.Eval(account,"Reference") 

获取基于字符串的属性,但使用它我无法为该属性分配值。

知道我该怎么做吗?

I have an instance of the Account class. Each account object has an owner, reference, etc.

One way I can access an accounts properties is through accessors like

account.Reference;

but I would like to be able to access it using dynamic string selectors like:

account["PropertyName"];

just like in JavaScript. So I would have account["Reference"] which would return the value, but I also would like to be able to assign a new value after that like:

account["Reference"] = "124ds4EE2s";

I've noticed I can use

DataBinder.Eval(account,"Reference") 

to get a property based on a string, but using this I can't assign a value to the property.

Any idea on how I could do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

桃酥萝莉 2024-09-09 11:18:10

首先,你应该避免使用这个; C# 是一种强类型语言,因此请充分利用该方面带来的类型安全和性能优势。

如果您有正当理由动态获取和设置属性的值(换句话说,当类型和/或属性名称无法在代码中定义时),那么您必须使用反射。

最内联的方式是这样的:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

但是,您可以缓存 PropertyInfo 对象以使其更具可读性:

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");

First of all, you should avoid using this; C# is a strongly-typed language, so take advantage of the type safety and performance advantages that accompany that aspect.

If you have a legitimate reason to get and set the value of a property dynamically (in other words, when the type and/or property name is not able to be defined in the code), then you'll have to use reflection.

The most inline-looking way would be this:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

However, you can cache the PropertyInfo object to make it more readable:

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");
恰似旧人归 2024-09-09 11:18:10

您可以尝试将索引器与反射结合起来......

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        property.SetValue(this,value, null);
    }
}

You could try combining the indexer with reflection...

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        property.SetValue(this,value, null);
    }
}
最偏执的依靠 2024-09-09 11:18:10

我使用了 Richard 的反射方法,但详细说明了 set 方法来处理正在使用的其他类型,例如字符串和空值。

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        Type propType = property.PropertyType;
        if (value == null)
        {
            if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
            {
                throw new InvalidCastException();
            }
            else
            {
                property.SetValue(this, null, null);
            }
        }
        else if (value.GetType() == propType)
        {
            property.SetValue(this, value, null);
        }
        else
        {
            TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
            object propValue = typeConverter.ConvertFromString(value.ToString());
            property.SetValue(this, propValue, null);
        }
    }
}

如果转换不起作用,SetValue() 函数将抛出错误。

I used the reflection method from Richard, but elaborated the set method to handle other types being used such as strings and nulls.

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        Type propType = property.PropertyType;
        if (value == null)
        {
            if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
            {
                throw new InvalidCastException();
            }
            else
            {
                property.SetValue(this, null, null);
            }
        }
        else if (value.GetType() == propType)
        {
            property.SetValue(this, value, null);
        }
        else
        {
            TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
            object propValue = typeConverter.ConvertFromString(value.ToString());
            property.SetValue(this, propValue, null);
        }
    }
}

The SetValue() function will throw an error if the conversion doesn't work.

落日海湾 2024-09-09 11:18:10

如果它们是您自己的对象,您可以提供索引器来访问这些字段。我真的不推荐这个,但它会允许你想要的。

public object this[string propertyName]
{
    get
    {
        if(propertyName == "Reference")
            return this.Reference;
        else
            return null;
    }
    set
    {
        if(propertyName == "Reference")
            this.Reference = value;
        else
            // do error case here            
    }
}

请注意,执行此操作时您会失去类型安全性。

If they are your own objects you could provide an indexer to access the fields. I don't really recommend this but it would allow what you want.

public object this[string propertyName]
{
    get
    {
        if(propertyName == "Reference")
            return this.Reference;
        else
            return null;
    }
    set
    {
        if(propertyName == "Reference")
            this.Reference = value;
        else
            // do error case here            
    }
}

Note that you lose type safety when doing this.

悍妇囚夫 2024-09-09 11:18:10

如果您使用的是.Net 4,您现在可以使用dynamic关键字。

dynamic foo = account;
foo.Reference = "124ds4EE2s";

If you are using .Net 4 you can use the dynamic keyword now.

dynamic foo = account;
foo.Reference = "124ds4EE2s";
最冷一天 2024-09-09 11:18:10

我同意之前的海报,您可能确实需要使用这些属性。与直接属性访问相比,反射非常慢。

另一方面,如果您需要维护用户定义属性的列表,则不能使用 C# 属性。您需要假装自己是一个 Dictionary,或者需要公开一个行为类似于 Dictionary 的属性。以下是如何使 Account 类支持用户定义属性的示例:

public class Account
{
    Dictionary<string, object> properties;
    public object this[string propertyName]
    {
        get
        {
            if (properties.ContainsKey[propertyName])
                return properties[propertyName];
            else
                return null;
        }
        set
        {
            properties[propertyName] = value;
        }
    }
}

I agree with the previous posters that you probably do need to be using the properties. Reflection is very slow compared to direct property access.

On the other hand, if you need to maintain a list of user-defined properties, then you can't use C# properties. You need to pretend you are a Dictionary, or you need to expose a property that behaves like a Dictionary. Here is an example of how you could make the Account class support user-defined properties:

public class Account
{
    Dictionary<string, object> properties;
    public object this[string propertyName]
    {
        get
        {
            if (properties.ContainsKey[propertyName])
                return properties[propertyName];
            else
                return null;
        }
        set
        {
            properties[propertyName] = value;
        }
    }
}
请叫√我孤独 2024-09-09 11:18:10

我个人更喜欢使用扩展方法,所以这是我的代码:

public static class ReflectionExtensions
{
    public static void SetPropertyValue(this object Target,
        string PropertyName,
        object NewValue)
    {
        if (Target == null) return; //or throw exception

        System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);

        if (prop == null) return; //or throw exception

        object value = prop.GetValue(Target, null);

        prop.SetValue(Target, NewValue, null);
    }
}

I personally prefer to work with extension methods so here is my code :

public static class ReflectionExtensions
{
    public static void SetPropertyValue(this object Target,
        string PropertyName,
        object NewValue)
    {
        if (Target == null) return; //or throw exception

        System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);

        if (prop == null) return; //or throw exception

        object value = prop.GetValue(Target, null);

        prop.SetValue(Target, NewValue, null);
    }
}
静赏你的温柔 2024-09-09 11:18:10

您需要使用反射:

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

请注意,这会非常慢。

You need to use Reflection:

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

Note that this will be very slow.

恰似旧人归 2024-09-09 11:18:10

使用反射体和表达式体

        public dynamic this[string memberName]
        {
            get => GetType().GetProperty(memberName).GetValue(this, null);
            set => GetType().GetProperty(memberName).SetValue(this,value, null);
        }

Use reflection and expression bodies

        public dynamic this[string memberName]
        {
            get => GetType().GetProperty(memberName).GetValue(this, null);
            set => GetType().GetProperty(memberName).SetValue(this,value, null);
        }
妥活 2024-09-09 11:18:10

如何通过字符串名称使用反射来访问对象中的列表
公共列表表1 { 得到;放; } = 新列表();

how to access the list in an object using reflection by string name
public List Table1 { get; set; } = new List();

獨角戲 2024-09-09 11:18:10

这是一个简单的例子,希望对您有所帮助

static void Main(string[] args)
{
    Operators op = new Operators()
    {
        ID = 1,
        Name = "Edward",
        email = "[email protected]",
        Pass = "123456",
        Auth1 = "EDF3242523@FFSDGDF"
    };

    var typei = op.GetType();
    var ss = typei.GetProperties().Where(m => m.GetCustomAttributes<Password>().Count() > 0);

    foreach (var item in ss)
    {
        var text = typei.GetProperty(item.Name).GetValue(op).ToString();
        
        typei.GetProperty(item.Name).SetValue(op, Encrypt(text));
    }

    Console.WriteLine(op.Pass);
    Console.WriteLine(op.Auth1);

    Console.ReadKey();
}

Here is a simple example, I hope it helps

static void Main(string[] args)
{
    Operators op = new Operators()
    {
        ID = 1,
        Name = "Edward",
        email = "[email protected]",
        Pass = "123456",
        Auth1 = "EDF3242523@FFSDGDF"
    };

    var typei = op.GetType();
    var ss = typei.GetProperties().Where(m => m.GetCustomAttributes<Password>().Count() > 0);

    foreach (var item in ss)
    {
        var text = typei.GetProperty(item.Name).GetValue(op).ToString();
        
        typei.GetProperty(item.Name).SetValue(op, Encrypt(text));
    }

    Console.WriteLine(op.Pass);
    Console.WriteLine(op.Auth1);

    Console.ReadKey();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文