C# 在不知道元素类型的情况下向列表中添加项

C# 在不知道元素类型的情况下向列表中添加项,c#,reflection,C#,Reflection,我需要用具体数据填写一份清单。此列表是另一个对象的属性。该列表的元素具有以下规则: 它们包含一个名为“Id”的可写int属性 它们有一个没有参数的构造函数 这是迄今为止的代码:(我没有添加任何合理性检查或错误处理来保持此示例的简单性) 公共字符串HouseName{get;set;] } 公共类组{ 公共字符串名称{get;set;} 公共列表用户{get;set;} 公共列表屋{get;set;} } var group=新组{Name=“nerds”}; SetListProperty(

我需要用具体数据填写一份清单。此列表是另一个对象的属性。该列表的元素具有以下规则:

  • 它们包含一个名为“Id”的可写int属性
  • 它们有一个没有参数的构造函数
这是迄今为止的代码:(我没有添加任何合理性检查或错误处理来保持此示例的简单性)

公共字符串HouseName{get;set;] }

公共类组{
公共字符串名称{get;set;}
公共列表用户{get;set;}
公共列表屋{get;set;}
}
var group=新组{Name=“nerds”};
SetListProperty(“用户”),组,新int[]{1,2,3,4,5});
SetListProperty(“房屋”),集团,新国际[]{1,2,3,4,5});
因此,在调用该方法之后,
group
应该包含一个属性
Users
,该属性有5个元素,每个元素都有Id集

关于创建未知类型的列表,我在这里看到了类似的问题,但没有看到如何实际将未知类型的单个项目添加到该列表中。

(更新) 我想一开始我的问题还不够清楚。在该方法中,我不知道属性类型。即使是一张单子也不行


我只有字符串形式的属性名

我放弃了最初的答案(如下),以便在不知道属性类型的情况下真正解决这个问题,除了它是一个具有id的项……或者它是一个具有id的对象的可枚举项

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace StackOverflowTests
{
    [TestClass]
    public class StackOverflow_49181925Tests
    {
        public interface IHasId
        {
            int Id { get; set; }
        }

        public class Foo : IHasId
        {
            public int Id { get; set; }
        }

        public class HasAFoo
        {
            public Foo Foo { get; set; }
        }

        public class HasManyFoos
        {
            public IEnumerable<Foo> Foos { get; set; }
        }

        public void SetPropertyIds(object target, string propertyName, IEnumerable<int> ids)
        {
            var property = target.GetType().GetProperty(propertyName);
            var propertyType = property.PropertyType;

            //is it enumerable?
            if (typeof(IEnumerable).IsAssignableFrom(propertyType))
            {
                var objectType = propertyType.GetGenericArguments().First();

                var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(objectType)) as IList;

                foreach(var id in ids)
                {
                    var obj = Activator.CreateInstance(objectType) as IHasId;
                    ((IHasId)obj).Id = id;

                    list.Add(obj);
                }

                property.SetValue(target, list);
            }
            else
            {
                if(ids.Count() != 1) throw new ApplicationException("You're trying to set multiple Ids to a single property.");
                var objectType = propertyType;
                var obj = Activator.CreateInstance(objectType);
                ((IHasId)obj).Id = ids.First();
                property.SetValue(target, obj);
            }
        }  

        [TestMethod]
        public void TestHasAFoo()
        {
            var target = new HasAFoo();
            this.SetPropertyIds(target, "Foo", new[] { 1 });
            Assert.AreEqual(target.Foo.Id, 1);
        }

        [TestMethod]
        public void TestHasManyFoos()
        {
            var target = new HasManyFoos();
            this.SetPropertyIds(target, "Foos", new[] { 1, 2 });
            Assert.AreEqual(target.Foos.ElementAt(0).Id, 1);
            Assert.AreEqual(target.Foos.ElementAt(1).Id, 2);
        }
    }
}
使用泛型:

group.Users = new[]{1,2,3}.Select(s=>new User{Id = s}).ToList();
private IList<T> IntsToModels<T>(IEnumerable<int> ints, Action<T,int> setId) where T : new(){

return ints.Select(s=>{
var t = new T();
setId(t,s);

return t;
}).ToList();

}
private IList IntsToModels(IEnumerable ints,Action setId),其中T:new(){
返回整数。选择(s=>{
var t=新的t();
setId(t,s);
返回t;
}).ToList();
}
使用泛型和接口

public interface IHasID{
int Id{get;set;}
}
//implement the IHasID interface
public class User : IHasID...

private IEnumerable<T> ToModels(IEnumerable<int> ints) where T : IHasID, new(){
foreach(var i in ints){
yield return new T{Id = i};
}
}
公共接口IHasID{
int Id{get;set;}
}
//实现IHasID接口
公共类用户:IHasID。。。
私有IEnumerable ToModels(IEnumerable ints),其中T:IHasID,new(){
foreach(内部变量i){
产生返回新的T{Id=i};
}
}

您可能希望尝试为此使用泛型和委托,而不是反射。另外,由于您处理的是引用类型,因此不需要
ref
。为什么不能直接创建此列表并将其分配给“group”对象?第一个(新)答案有效。我不能使用接口(用于Id),所以我必须使用反射来设置接口,但我的主要问题已经解决了。谢谢
group.Users = new[]{1,2,3}.Select(s=>new User{Id = s}).ToList();
private IList<T> IntsToModels<T>(IEnumerable<int> ints, Action<T,int> setId) where T : new(){

return ints.Select(s=>{
var t = new T();
setId(t,s);

return t;
}).ToList();

}
public interface IHasID{
int Id{get;set;}
}
//implement the IHasID interface
public class User : IHasID...

private IEnumerable<T> ToModels(IEnumerable<int> ints) where T : IHasID, new(){
foreach(var i in ints){
yield return new T{Id = i};
}
}