C# 如何使用反射修改集合中的特定项

C# 如何使用反射修改集合中的特定项,c#,reflection,C#,Reflection,我需要使用反射来修改集合中的一个项-我使用反射是因为在运行时之前我不知道泛型集合的确切类型 我知道如何使用SetValue方法来设置通过集合检索的属性的值,但是我可以使用SetValue来设置集合中的实际对象吗 IEnumerable businessObjectCollection = businessObject as IEnumerable; foreach (Object o in businessObjectCollection) { // I want to set the

我需要使用反射来修改集合中的一个项-我使用反射是因为在运行时之前我不知道泛型集合的确切类型

我知道如何使用SetValue方法来设置通过集合检索的属性的值,但是我可以使用SetValue来设置集合中的实际对象吗

IEnumerable businessObjectCollection = businessObject as IEnumerable;

foreach (Object o in businessObjectCollection)
{
    // I want to set the "o" here to some replacement object in the collection if
    // a property on the object equals something
    Type t = o.GetType();
    PropertyInfo identifierProperty = o.GetType().GetProperty("Identifier");
    long entityID = (long)identifierProperty.GetValue(o, null);


    if (replacementEntity.Identifier == entityID)
    {
        // IN THIS CASE: set "o" to be the replacementEntity object
        // defined somewhere else. 

        // I can retrieve the object itself using this code, but
        // would I set the object with SetValue?
        object item = businessObjectCollection.GetType().GetMethod("get_Item").Invoke(businessObjectCollection, new object[] { 1 });                              
    }

}
好的,您可以使用get_Item来检索它,因此您应该能够调用set_Item来设置它:

businessObjectCollection.GetType().GetMethod("set_Item").Invoke(businessObjectCollection, new object[] { 1, replacementEntity });

请注意,如果集合不是支持索引访问的类型,则此操作将爆炸。

您可以使用一个新的枚举来替换它,而不是尝试修改枚举,以执行内联替换。这真的取决于你以后用它做什么,尽管如此

IEnumerable newCollection = businessObjectCollection.Cast<object>().Select((o) =>
{
    Type t = o.GetType();
    PropertyInfo identifierProperty = o.GetType().GetProperty("Identifier");
    long entityID = (long)identifierProperty.GetValue(o, null);

    if (replacementEntity.Identifier == entityID)
    {
        return replacementEntity;
    }
    return o;
});

此方法将对象添加到对象上所述对象的集合属性中

obj是包含属性集合的父对象

propertyName是集合属性的名称

值是要添加到集合中的对象

private object AddItemToCollectionProperty( Object obj, string propertyName, Object value )
    {
        PropertyInfo prop = obj.GetType().GetProperty( propertyName );
        if( prop != null )
        {
            try
            {
                MethodInfo addMethod = prop.PropertyType.GetMethod( "Add" );

                if(addMethod ==null)
                {
                    return obj;
                }

                addMethod.Invoke( prop.GetValue(obj), new object [] { value }  );

            }
            catch( Exception ex )
            {
                Debug.Write( $"Error setting {propertyName} Property Value: {value} Ex: {ex.Message}" );
            }
        }
        else
        {
            Debug.Write( $"{propertyName} Property not found: {value}" );
        }

        return obj;
    }

您知道您的集合将是可修改的吗?businessObjectCollection是什么类型的?无法修改IEnumerable。如果您想假设您有能力修改IEnumerable,则必须将IEnumerable更改为IList或ICollection;这是一个糟糕的jujuju,很可能最终会出现一个异常,告诉您C集合被修改了;枚举操作可能无法执行。是否可以替换对集合的引用?i、 e.是否用新对象替换businessObjectCollection?如果是这样的话,可能有几种方法可以做到这一点,而不必修改原始的潜在不可修改的对象。哦,伙计,这太接近了!!它正做着我想要的事情,只是我不能将这个新的IEnumerable分配给我的第二个对象来替换集合。出现了一个异常,表明IEnumerable类型的对象不能转换为泛型列表类型。有没有一种方法可以将这个IEnumerable转换成我在运行时寻找的类型的泛型列表?我想我需要更多地了解如何使用它。如果这个操作的结果以后需要可变,那么您选择的路径似乎会更好。它确实提出了一个问题,为什么对象会从列表->可枚举->列表,但这并不在回答这个问题的范围之内:
private object AddItemToCollectionProperty( Object obj, string propertyName, Object value )
    {
        PropertyInfo prop = obj.GetType().GetProperty( propertyName );
        if( prop != null )
        {
            try
            {
                MethodInfo addMethod = prop.PropertyType.GetMethod( "Add" );

                if(addMethod ==null)
                {
                    return obj;
                }

                addMethod.Invoke( prop.GetValue(obj), new object [] { value }  );

            }
            catch( Exception ex )
            {
                Debug.Write( $"Error setting {propertyName} Property Value: {value} Ex: {ex.Message}" );
            }
        }
        else
        {
            Debug.Write( $"{propertyName} Property not found: {value}" );
        }

        return obj;
    }