【问题标题】:Adding an instance of a type to a list of that type when instantiated by reflection通过反射实例化时将类型的实例添加到该类型的列表中
【发布时间】:2014-11-28 15:44:14
【问题描述】:

我正在尝试通过使用反射来填充几个类的属性,以将默认值分配给它们的所有属性。

这主要是通过使用 PropertyInfo.Setvalue(instance, value) 来完成的。但是,当该属性具有特定类的列表时,我遇到了问题。直到运行时我才知道该类类型。

要创建该列表并返回到 SetVaule() 设置,我正在执行以下操作:

    private static IEnumerable<object> CreateAListContainingOneObject(Type type)
    {
        var listType = typeof(List<>).MakeGenericType(new Type[] { type });
        var generic = Activator.CreateInstance(listType);
        var dynamicList = generic as dynamic;

         var instance = new MySpecialType();
         var instance2 = Activator.CreateInstance(type);

        var typecheck = instance.GetType() == instance2.GetType();

        dynamicList.Add(instance);
        dynamicList.Add(instance2);
        return dynamicList;
    }

我已经尝试了几个选项,但是这里列出的一个特别有趣,因为当运行时类型检查将为真,第一个 Add 将起作用,但第二个将失败,告诉我“最好的重载方法 'Add(. ...)' 有一些无效的参数”。

PS。该列表必须是 MyType 的列表,否则我将无法通过 SetVaule() 将其值设置为属性。使用新的对象列表并添加我新实例化的 myType 类型的对象将不起作用。

编辑:我没有使用泛型方法来调用我可以实例化已知类型的原因是因为我在从我的基类继承的一系列类上执行此操作。他们有各种各样的属性,我不知道也不想为每个类和它可以拥有的每个属性编写代码。 调用来自以下内容:

public static ABaseClass FillObjectWithDefaults(this ABaseClass myObject)
    {
        var properties = myObject.GetType().GetProperties();
        foreach (var p in properties)
        {
             var value = FindValue(p);
             p.SetValue(template, value);
        }
        return template;
    }

【问题讨论】:

    标签: c# generics reflection


    【解决方案1】:

    您可以使用第二种通用​​方法来帮助您,因此您无需搞乱动态和激活。

    这仅涉及查找辅助方法并调用该方法以创建实例并将其添加到列表中。它还为您提供了通用调用它的选项。

    private static IEnumerable<object> CreateAListContainingOneObject(Type type)
    {
        var del = typeof(Program).GetMethod("CreateAGenericListContainingOneObject",
            BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type);
    
        return del.Invoke(null, new object[] { }) as IEnumerable<object>;
    }
    
    private static List<T> CreateAGenericListContainingOneObject<T>()
        where T : new()
    {
        return new List<T> { new T() };
    }
    

    Example DotNetFiddle

    【讨论】:

    • 这行得通。我试图做这样的事情,但无法让它发挥作用。现在它适用于我需要创建的任何对象,并且无需担心额外的或特定于案例的代码。
    【解决方案2】:

    Activator.CreateInstance 返回一个Object 类型的对象,所以第二个Add 不能工作。

    你可以选择它:

    var instance2 = Activator.CreateInstance(type) as MySpecialType;
    var instance2 = (MySpecialType)Activator.CreateInstance(type);
    

    或者用dynamic代替var:

    dynamic instance2 = Activator.CreateInstance(type);
    

    就个人而言,我可能会完全更改函数以使用这样的泛型类型参数:

    private static IEnumerable<object> CreateAListContainingOneObject<T>()
    {
        var listType = typeof(List<>).MakeGenericType(typeof(T));
        var generic = Activator.CreateInstance(listType);
        var dynamicList = generic as dynamic;
    
        var instance = new MySpecialType();
    
        var instance2 = (T)Activator.CreateInstance(typeof(T));
    
        var typecheck = instance.GetType() == instance2.GetType();
    
        dynamicList.Add(instance);
        dynamicList.Add(instance2);
        return dynamicList;
    }
    

    然后这样称呼它:

    var list = CreateAListContainingOneObject<MySpecialType>();
    

    【讨论】:

    • 我的情况的问题是我在编译时不知道类型,所以我不能按类型调用泛型方法。我标记为正确的答案解决了我在将我的运行时已知类型应用于它之后通过反射调用泛型方法来获取正确类型的问题。
    • 然后坚持使用dynamic,这应该适合你。但任何适合你的答案都很棒:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多