Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将实例化的System.Type作为泛型类的类型参数传递_C#_.net_Generics - Fatal编程技术网

C# 将实例化的System.Type作为泛型类的类型参数传递

C# 将实例化的System.Type作为泛型类的类型参数传递,c#,.net,generics,C#,.net,Generics,标题有点晦涩难懂。我想知道的是这是否可行: string typeName = <read type name from somwhere>; Type myType = Type.GetType(typeName); MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>(); stringtypename=; 类型myType=Type.GetType(类型名称); MyGe

标题有点晦涩难懂。我想知道的是这是否可行:

string typeName = <read type name from somwhere>;
Type myType = Type.GetType(typeName);

MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>();
stringtypename=;
类型myType=Type.GetType(类型名称);
MyGenericClass MyGenericClass=新的MyGenericClass();
显然,MyGenericClass被描述为:

public class MyGenericClass<T>
公共类MyGenericClass

现在,编译器抱怨找不到“类型或命名空间”myType。“必须有办法做到这一点。

不幸的是,没有办法。泛型参数必须在编译时可解析为1)有效类型或2)另一个泛型参数。如果不使用反射,就无法基于运行时值创建通用实例。

如果没有反射,就无法做到这一点。但是,您可以通过反射来实现。下面是一个完整的示例:

using System;
using System.Reflection;

public class Generic<T>
{
    public Generic()
    {
        Console.WriteLine("T={0}", typeof(T));
    }
}

class Test
{
    static void Main()
    {
        string typeName = "System.String";
        Type typeArgument = Type.GetType(typeName);

        Type genericClass = typeof(Generic<>);
        // MakeGenericType is badly named
        Type constructedClass = genericClass.MakeGenericType(typeArgument);

        object created = Activator.CreateInstance(constructedClass);
    }
}
public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}
使用系统;
运用系统反思;
公共类泛型
{
公共泛型()
{
WriteLine(“T={0}”,typeof(T));
}
}
课堂测试
{
静态void Main()
{
string typeName=“System.string”;
Type typeArgument=Type.GetType(typeName);
类型genericClass=typeof(通用);
//MakeGenericType的名称不正确
类型constructedClass=genericClass.MakeGenericType(类型参数);
创建的对象=Activator.CreateInstance(constructedClass);
}
}
注意:如果泛型类接受多个类型,则在省略类型名称时必须包含逗号,例如:

Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);
Type genericClass=typeof(IReadOnlyDictionary);
类型constructedClass=genericClass.MakeGenericType(typeArgument1,typeArgument2);

使用剪刀式代码运行的一些附加方法。假设您有一个类似于的类

public class Encoder() {
public void Markdown(IEnumerable<FooContent> contents) { do magic }
public void Markdown(IEnumerable<BarContent> contents) { do magic2 }
}
注意方法调用中使用的
dynamic
。在运行时,
dynamicList
将是
List
(另外也是
IEnumerable
),因为即使动态的使用仍然是基于强类型语言,运行时绑定器也会选择适当的
标记方法。如果没有完全匹配的类型,它将查找对象参数方法,如果两者都不匹配,将引发运行时绑定异常,警告没有匹配的方法


这种方法的明显缺陷是编译时类型安全性的巨大损失。尽管如此,沿着这些思路编写的代码将让您在一个非常动态的意义上操作,即在运行时仍然是完全类型化的,正如您所期望的那样。

我的要求略有不同,但希望能帮助到某些人。我需要从配置中读取类型并动态实例化泛型类型

namespace GenericTest
{
    public class Item
    {
    }
}

namespace GenericTest
{
    public class GenericClass<T>
    {
    }
}

如果您知道将要传递的类型,则可以不经过反射地执行此操作。switch语句可以工作。显然,这只在有限的情况下有效,但比反射快得多

public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}
公共类类型1{}
公共类类型2{}
公共类泛型{}
公共课程
{
公共静态void Main()
{
var typeName=名称(类型1);
开关(类型名称)
{
案例名称(类型1):
var type1=新的泛型();
//做点什么
打破
案例名称(类型2):
var type2=新的泛型();
//做点什么
打破
}
}
}

在这段代码中,我想展示如何创建和使用动态创建的列表。例如,我在这里添加到动态列表中

void AddValue<T>(object targetList, T valueToAdd)
{
    var addMethod = targetList.GetType().GetMethod("Add");
    addMethod.Invoke(targetList, new[] { valueToAdd } as object[]);
}

var listType = typeof(List<>).MakeGenericType(new[] { dynamicType }); // dynamicType is the type you want
var list = Activator.CreateInstance(listType);

AddValue(list, 5);
void AddValue(对象目标列表,T值添加)
{
var addMethod=targetList.GetType().GetMethod(“添加”);
Invoke(targetList,new[]{valueToAdd}作为对象[]);
}
var listType=typeof(List).MakeGenericType(new[]{dynamicType});//dynamicType是您想要的类型
var list=Activator.CreateInstance(listType);
附加值(列表,5);

同样,您可以调用列表中的任何其他方法。

泛型!=模板。所有泛型类型变量都在编译时解析,而不是在运行时解析。这是4.0的“动态”类型可能有用的情况之一。@Will-以什么方式?当与泛型一起使用时,在当前的CTP下,您基本上会调用版本(除非我错过了一个技巧…@marcGravel您可以使用
foo.Method((动态)myGenericClass)
进行运行时方法绑定,实际上是类型方法重载的服务定位器模式。@chrismaric yes,对于一些通用的
公共无效方法(tobj)
——自从那次评论以来,在过去的6年里,我已经使用了不止一次的技巧;p@MarcGravell有没有一种方法可以修改它,以便方法实例化它?好的,这很好,但是如何在创建的对象上调用方法呢?更多的反射?好吧,如果你可以让你的泛型类型实现一个非泛型接口,你可以转换到那个接口。或者,你可以编写你自己的泛型方法,它完成你想用泛型做的所有工作,并用反射调用它。是的,我不明白如果关于返回类型的唯一信息是在typeArgument类型变量中,如何使用created?在我看来,你可能需要对这个变量进行转换,但你不知道它是什么,所以我不确定你是否可以通过反射来实现。另一个问题是,如果对象是int类型的示例,如果您将其作为对象变量传递到示例的列表中,那么这项工作将如何进行?创建的变量是否会被视为int?@RobertC.Barth您还可以将示例中的“created”对象类型设置为“dynamic”而不是“object”。这样,您就可以对其调用方法,并且计算将推迟到运行时。@balanza:您使用MakeGenericMethod。一旦您开始处理100个类,这种情况就会变得很糟糕。
var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest");
var a = Activator.CreateInstance(t);
public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}
void AddValue<T>(object targetList, T valueToAdd)
{
    var addMethod = targetList.GetType().GetMethod("Add");
    addMethod.Invoke(targetList, new[] { valueToAdd } as object[]);
}

var listType = typeof(List<>).MakeGenericType(new[] { dynamicType }); // dynamicType is the type you want
var list = Activator.CreateInstance(listType);

AddValue(list, 5);