【问题标题】:Generic class where T : Class clarification泛型类,其中 T :类说明
【发布时间】:2017-04-13 12:14:30
【问题描述】:

这个问题有半个答案,我已经彻底阅读过,以及 MSDN 关于泛型类的所有内容,但是当泛型类从另一个类继承时我仍然遇到问题:where T: ClassName

例如,这是我的通用列表类

public class MyGenericList2<T> where T : Person
{
    private T[] list;

    public MyGenericList2(int size)
    {
        list = new T[size];
    }

    public T getItem(int index)
    {
        T temp = default(T);
        temp = list[index];
        return temp;
    }

    public void setItem(int index, T value)
    {
        list[index] = value;
    }

    public void DisplayList()
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Out.WriteLine(list[i]);
        }
    }
}

它继承自 person 类: 注意:为了清楚起见,它被缩短了

public abstract class Person
{
    protected string firstName;

    // Getters
    public string getFirstName()
    {
        return this.firstName;
    }
    public void setFirstName(string fname)
    {
        this.firstName = fname;
    }
}

当我尝试调用它时,我收到一个关于尝试将字符串转换为 {namespace}.Person 的错误,因为我试图将字符串放入“Person”框中,但是如何使用这种机制调用类吗?

这里是主要方法

public static void Main(string[] args)
{
    MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
    Student st1 = new Student();

    st1.setFirstName("Thor");
    studentGeneric.setItem(0, st1); //This does not work
    studentGeneric.setItem(1, Person.setFirstName("Odin"); // Does not work
    studentGeneric.setItem(2, st1.setFirstName("Slepnir"); // Does not work
    studentGeneric.DisplayList();
    Console.ReadLine();
}

如果我剪掉Where T : Person 并使用GenericList2&lt;string&gt;,它可以正常工作,这是有道理的,因为它是字符串到字符串的。

任何帮助将不胜感激

快速澄清 Student 从 Person 继承:

public class Student : Person
{

    // Student 1
    private string studentID01 = "001";

    public string getStudentID01()
    {
        return this.studentID01;
    }
}

【问题讨论】:

  • 学生是否从人继承?
  • 对不起,是的。修复代码
  • 第一个例子确实有效 --> studentGeneric.setItem(0, st1);其他的将不起作用,因为它们不是 Person 类型。您不会在方法参数中传递 setter 方法。 setter 方法不返回值(通常),即使它确实返回了值,它们也必须是 Person 类型,setItem 方法才能编译。
  • 是的,它确实可以编译,但是它在程序运行时返回的值,我原以为它是字符串“Thor”,而是显示namespace.Person
  • 您需要覆盖 Student 类中的 toString() 方法,或者如果您有学生类的 getFirstName() 方法,请在 MyGenericCollection 中更改此方法 --> Console.Out.WriteLine (列表[i]);到这个 Console.Out.WriteLine(list[i].getFirstName());

标签: c# generics


【解决方案1】:

首先,我建议为您的类使用公共属性,例如:

public abstract class Person
{
    public string FirstName { get; set; }   
}

public class Student : Person
{
    public string StudentId { get; set; }
}

这意味着您的列表代码将像这样工作:

Student st1 = new Student();
st1.FirstName = "Thor";
studentGeneric.setItem(0, st1);

你甚至可以使用这个语法:

studentGeneric.setItem(1, new Student
{
    FirstName = "Odin"
});

此外,.Net 框架已经提供了一组非常好的通用集合类,您可以使用这些类,因此您并不需要您的 MyGenericList2&lt;T&gt; 类。比如最常用的类是System.Collections.Generic.List

var people = new System.Collections.Generic.List<Person>();

people.Add(new Student
{
    FirstName = "Odin"
});

甚至使用集合初始化语法:

var people = new System.Collections.Generic.List<Person>
{    
    new Student
    {
        FirstName = "Odin"
    }
});

最后,将值输出到控制台时遇到的问题是因为 C# 不知道如何处理您的类,因此默认情况下输出 student.ToString() 的值。而且因为你没有告诉你的班级如何处理它,它只是输出类型的名称。您可以覆盖ToString,或者更简单的是调用getFirstName() 方法:

Console.WriteLine(list[i].getFirstName());

【讨论】:

  • 这很有帮助。我可能最终会使用内置插件,但与我的长手 setter 和 getter 一样(而不是使用 {get; set;},我希望通过手卷类来完成这项工作。当我添加 MyGenericList2 类时Console.Out.WriteLine(list[i].ToString());Console.Out.WriteLine(list[i].getFirstName()); 它会抛出异常声明 System.NullReferenceException: 'Object reference not set to an instance of an object.'
  • 如果您没有在数组中的每个位置创建一个学生,就会发生这种情况,否则这些空值将为 null,您无法对其调用方法。
  • 那行得通^_^我不知道为什么我没有意识到这一点。谢谢你。我确实必须使用getFirstName(),否则它只会打印namespace.classname
【解决方案2】:

您错误地使用了setItem。此方法可用于在MyGenericList2 类的实例中设置list 数组中元素的值。

要在 Student 类的实例上使用 setFirstName 方法,首先使用 getItem 返回对象实例。例如:

public void Main(string[] args)
{
    MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);

    Student st1 = new Student();
    st1.setFirstName("Thor");
    studentGeneric.setItem(0, st1);

    Student st2 = new Student();
    studentGeneric.setItem(1, st2);
    studentGeneric.getItem(1).setFirstName("Odin");

    Student st3 = new Student();
    studentGeneric.setItem(2, st3);
    studentGeneric.getItem(2).setFirstName("Slepnir");

    studentGeneric.DisplayList();
    Console.ReadLine();
}

要正确显示列表内容,请将您的 DisplayList() 方法替换为:

public void DisplayList()
{
    for (int i = 0; i < list.Length; i++)
    {
        if(list[i] != null){
            Console.Out.WriteLine("{0}: {1}", i, list[i].getFirstName());
        }
        else
        {
            Console.Out.WriteLine("{0}: [NULL]", i);
        }
    }
}

【讨论】:

  • 是的,这很有帮助。但是,再一次,我不确定为什么或如何,我认为它是我的泛型类本身,但是当我运行程序时,输出显示 StudentLookup.Person StudentLookup 是命名空间
  • DisplayList 方法中的逻辑不正确。我用不同的实现修改了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
相关资源
最近更新 更多