C# 泛型类 构造方法中实例化T

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 泛型类 构造方法中实例化T相关的知识,希望对你有一定的参考价值。

在c#中:
public class AA<T> where T :class

public T[] t;
public AA ()

t = new T[10]; // 可以直接实例化。


public class AA<T> where T :class

public T t;
public AA ()

t = new T(); // 出错,提示: 变量类型“T”没有 new() 约束,因此无法创建该类型的实例


public class AA<T> where T :new ()

public T t;
public AA ()

t = new T(); // 成功



问题:为什么,t=new T(),需要约束。而 t = new T[10]; 不需要约束?请详细解答, 谢谢!

你好

    t = new T[10];  这句代码是【创建】一个T类型的长度为10的【数组】。

    数组中的值为全部为null。就是说创建了数组,没有创建T类型的对象。


   t = new T();这句代码是【创建】一个T类型的【对象】。

   但是T类型中可能没有无参的构造器。如:

 public class Person
    
        public Person(string name)
        
            Name = name;
        
        public string Name  get; set; 
    

使用约束

public class AA<T> where T :new ()

  就是保证T类型必须有一个无参构造器。保证对象一定能被构造。

参考技术A 泛型类:
public class MyClass<T>

public T MyElement get; set;

泛型函数:
public T ReturnElement<T>()

throw new NotImplementedException();


但是当需要对MyElement进行实例化的时候,却不能使用new(),只要添加如下代码即可进行实例化了:
泛型类:
public class MyClass<T> where T: new()

public T MyElement get; set;

public MyClass()

this.MyElement = new T();



泛型函数:
public T ReturnElement<T>() where T : new()

return new T();


在这里,where实际上对泛型类型T的一个限定或补充。如果你希望T是一个int的集合,这个集合可以是List<int>,也可以是HashSet<int>等等,只要它们都是从ICollection继承而来的,则可以添加对类型T的限定,同时要保证它还是可以实例化的:
public T ReturnElement<T>()
where T : ICollection<int>, new()

return new T();


进一步,如果希望放宽集合中元素的类型,比如只要是int,double等可比较的类型,它们都是从IComparable继承而来,则可以继续添加如下限定:
public T ReturnElement<T, S>()
where T : ICollection<S>, new()
where S : IComparable

return new T();
参考技术B 不同的T构造的方式是不同的,有点需要1000字节的内存,有的需要8字节内存。而数组不同,它只是个容器,占用内存统一是一个引用,等你给数组这个容器里添加实际内容的时候,同样需要约束,比如t = new T[10]; t[0]=new T();后一句才是真正的new了一个T,前一句只是声明容器。 参考技术C new T[10]只是声明,还没赋值,只是10个空指针,你知道不管是什么对象的指针都基本是个整数,所以和类型无关。而new是实实在在地开辟了T类型的空间。 参考技术D public T[ ] t 是数组,不需要new本回答被提问者采纳

详解C#泛型

  一、前面两篇文章分别介绍了定义泛型类型、泛型委托、泛型接口以及声明泛型方法:

  详解C#泛型(一)

  详解C#泛型(二)

  首先回顾下如何构建泛型类:

public class MyClass<T>
{
    public void MyFunc()
    {
        //
    }
}

  其中,尖括号<>中的T代表的是该泛型类的类型参数,在使用时可以指定其类型,例如,指定类型参数为整数类型,创建封闭式构造类MyClass<int>:

MyClass<int> myObj = new MyClass<int>();

  二、这一篇我们了解一下泛型的作用机制,泛型是运行时起作用的一套机制,根据运行时类型参数被指定为值类型还是引用类型其使用方式有所不同:

  1.当类型参数被指定为值类型时,会在第一次指定该特定值类型的类型时创建该类型唯一的专用化泛型类型,泛型类型中的类型参数会被替换为相应的值类型;

  ※此时,运行时会创建不同封闭式构造类型的类型信息对象,它们的类型句柄指向不同的类型信息对象,不同封闭式构造类型的方法句柄也指向不同的方法信息对象;

  2.当类型参数被指定为引用类型时,会在第一次指定任意引用类型时创建一个通用化泛型类型,泛型类型中的类型参数会被替换为该引用类型,并在之后每次指定为引用类型时重用该泛型类型并修改其中类型参数的类型;造成这种差异的原因可能在于所有的引用大小相同;

  ※此时,运行时依然会创建不同封闭式构造类型的类型信息对象,它们的类型句柄也指向不同的类型信息对象,但是它们共用一套方法句柄,即不同封闭式构造类型的方法句柄指向同一个方法信息对象;
  3.对于给定的泛型类:

public class MyClass<T>
{
    public void MyFunc()
    {
        //…
    }
}
获取不同封闭式构造类型的类型句柄和方法句柄:
Type type1 = typeof(MyClass<int>);
Type type2 = typeof(MyClass<long>);
Type type3 = typeof(MyClass<string>);
Type type4 = typeof(MyClass<Array>);
//以下类型句柄各不相同
Console.WriteLine(type1.TypeHandle.Value);
Console.WriteLine(type2.TypeHandle.Value);
Console.WriteLine(type3.TypeHandle.Value);
Console.WriteLine(type4.TypeHandle.Value);
//最后两个方法句柄相同,其它方法句柄各不相同
Console.WriteLine(type1.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type2.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type3.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type4.GetMethod("MyFunc").MethodHandle.Value);

  ※在访问任何泛型类型之前,CLR会先创建MyClass<>的类型信息对象;

  打印结果:

  技术分享图片

  可以发现,最后两个泛型类型的MyFunc方法的方法句柄指向相同;但是不同类型参数的情况下,还是会创建对应的泛型类型对象,这使得泛型单例成为可能:

  三、对于封闭式构造类型,只要其类型参数不完全相同,CLR就会在初次访问该类型之前创建该类型的类型信息对象并调用其对应唯一的静态构造函数,例如对于有静态构造函数的泛型类MyClass<T>,在初次访问MyClass<int>、MyClass<string>等封闭式构造类之前都会调用一次其对应唯一的静态构造函数,这也是创建泛型单例的基础:

public class MyClass<T>
{
    static MyClass()
    {
        Console.WriteLine(typeof(T).FullName);
    }
}
MyClass<int> obj1 = new MyClass<int>();
MyClass<long> obj2 = new MyClass<long>();
MyClass<Array> obj4 = new MyClass<Array>();  

  打印结果:

  技术分享图片

  四、运行时动态构建泛型:

Type myType = typeof(MyClass<>);  //获取未指定任何类型参数的开放式构造类的类型信息,多个类型参数时添加,:typeof(MyClass<,>)
myType = myType.MakeGenericType(typeof(int));  //通过类型信息的实例方法MakeGenericType()构建指定所有类型参数的封闭式构造类的类型信息,如未指定所有类型参数会抛出异常ArgumentException
//也可以直接获取封闭式构造类的类型信息,当类型参数在一开始就确定时推荐使用此种方式
//myType = typeof(MyClass<int>);  //多个类型参数时需要同时指定:typeof(MyClass<int, string>)

  注意:通过反射只可以获取未指定任何类型参数的开放式构造类MyClass<,>的类型信息和指定所有类型参数的封闭式构造类MyClass<int, string>的类型信息,即无法获取MyClass<int, >的类型信息;

 


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。



以上是关于C# 泛型类 构造方法中实例化T的主要内容,如果未能解决你的问题,请参考以下文章

c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?

Java:使用具有泛型构造函数的构建模式时“无法解析方法”

详解C#泛型

使用反射为泛型类创建构造函数

C# 泛型的使用

c# 自定义的一个泛型类可以序列化吗?