创建新类实例时语句的左侧和右侧的说明

时间:2016-10-29 16:36:59

标签: c#

我有一个班级

public class Table
{
    public string color {get; set;}
    public string height {get; set;}
}

当我想创建这个类的新实例时,我使用:

//1.
var myTable = new Table();

//2.
Table myTable = new Table();

//3.
IEnumerable<Table> Tables = new List<Table>();

但不是

//4.
List<Table> y = new IEnumerable<Table>();

有人可以解释左侧(var / Table / IEnumerable)正在做什么以及右侧(新表/新List()等)正在做什么。

为什么它们有时相同(例如2)而在其他时间不同(例如3)。

这三者之间的区别是什么:

var Tables = new List<Table>();
List<Table> Tables = new List<Table>();
IEnumerable<Table> Tables = new List<Table>();

我知道这是基本的东西,但我没有找到一个明确的解释,说明在C#中创建类的实例时,语句的左侧和右侧的含义是什么。

THX。

4 个答案:

答案 0 :(得分:2)

左侧指定变量的类型。就像在int i;中一样,单词int表示i是一个整数。而var意味着你懒得写类型名称,并且你想编译猜测你想要使用的类型。

这很容易。

右侧是您为变量指定的值。与int i = 10;一样,10存储在i

Table myTable = new Table();

new Table()的值存储在myTable

new Table()做了什么?好吧,它只是创建了一个Table的新实例。

这也很容易。

换句话说,您所做的只是创建Table的新实例并将其放入名为myTable的变量中。它就像:

int i = 1 + 1;

您可以通过添加1到1来创建新的整数2,然后将结果分配给i

  

为什么双方会有所不同?

就像在int i = 1 + 1;中一样,右侧不需要与左侧相同(有时它们必须不同)。因为你在这里所做的只是为一个变量赋值,只要右边的值可以放在左边的变量中,就没关系了!

现在有了困难的部分。

  

为什么这样做?

IEnumerable<Table> Tables = new List<Table>();

因为List<Table>的实例可以放入IEnumerable<Table>的实例中。就这么简单!

  

为什么List<Table>的实例可以放入IEnumerable<Table>的实例?

因为List<T>实现了接口IEnumerable<T>。因此,List<T>包含IEnumerable<T>中的所有方法。

  

为什么这不起作用?

List<Table> y = new IEnumerable<Table>();

首先,您无法通过new XXX()创建接口实例。您应该了解有关接口如何在C#中工作的更多信息。其次,类型为IEnumerable<T>的对象与List<T>不兼容。

仍然不明白为什么类型为IEnumerable<T>的对象与List<T>不兼容?

你基本上是这样做的:

int i = 1.234;

doubleint只是不要一起去!

答案 1 :(得分:1)

简而言之:

右侧创建实际对象,左侧创建对象的引用。

长期:

右手边创造了实际物体,我想这里没有任何神秘感。您无法执行new IEnumerable<Table>()因为IEnumerable是一个界面,而不是一个clss。您只能从类创建对象。

然后你需要将这个对象分配给某个引用并声明引用的类型。

List<Table> Tables = new List<Table>();

这很简单,您的参考与您的对象具有相同的类型。

IEnumerable<Table> Tables = new List<Table>();

这涉及到类的继承。如果您转到类List的源代码,您会看到List实现接口IEnumberable。因此,在定义引用时,您可以使用已实现的接口和扩展类而不是实际的类名。

这有一些额外的好处,这样您就可以将实现IEnumerable<Table>的其他类中的对象分配给Tables

var Tables = new List<Table>();

这种风格最近才出现。基本上,如果您不打算给引用赋予任何类型,编译器可以为您推导出一个类型。如果您将鼠标移到var,您将看到推断类型。如果您没有找到合适的推断类型,您可以随时自行编写类型。

答案 2 :(得分:1)

在所有情况下,您都要实例化您的Table类。最基本的实例化是案例2:

Table myTable = new Table();

你实际上是在说,给我一个名为myTable的Table类的实例,以便在本地工作。

在使用var关键字的情况1中,除了隐式键入myTable之外,您正在执行相同的操作。编译器决定myTable应该是什么类型。它仍然是Table类的一个实例,仍然是强类型的。

List<T>实现了接口IEnumerable<T>。所有List<T>'s都是IEnumerable<T>'s,并且可以像在案例3中那样实例化。当以这种方式实例化时,您无法访问特定于IList<T>接口的方法,并且只能访问IEnumerable<T>接口的方法。

案例4至少有几个原因不起作用。首先,您无法实例化接口。其次,即使你可以,但并非所有IEnumerable<T>'s都是List<T>'s。阅读继承,您将开始了解这种情况。

答案 3 :(得分:0)

正如其他人所提到的,并非所有IEnumerable<T>都是List<T>。一个相关的例子将清楚说明。

IEnumerable<int> ints = new int[5];
List<int> intsList = ints; //does not compile!

一个int数组与一个int列表不同,即使它们都实现了IEnumerable。更为明显的是词典。显然,词典具有与列表不同的方法和属性:

IEnumerable<KeyValuePair<string, string>> keyvals = new Dictionary<string,string>();
List<KeyValuePair<string,string>> keyvalList = keyvals; //does not compile!

你看,当你这样做时:

IEnumerable<KeyValuePair<string, string>> keyvals = new Dictionary<string,string>();

你失去了字典特定的功能。例如,您不能这样做:

keyvals.ContainsKey("foo");

IEnumerable<KeyValuePair<string,string>>未定义ContainsKey方法。实际上,基本上所有IEnumerable<T>都会公开GetEnumerator()和一些扩展方法。

IEnumerable<T>仍然非常有用。考虑定义接收IEnumerable<Table>的通用方法的this LinqPad script。你可以发送一个表数组或表格列表或表格堆栈等,它仍然可以工作:

void Main()
{
    IEnumerable<SomeTable> arrayOfSomeTable = 
        new SomeTable[] { new SomeTable(), new SomeTable() };

    IEnumerable<SomeTable> listOfSomeTable = 
        new List<SomeTable> { new SomeTable(), new SomeTable() };

    Stack<SomeOtherTable> stackOfOtherTable = new Stack<SomeOtherTable>();
    stackOfOtherTable.Push(new SomeOtherTable());
    stackOfOtherTable.Push(new SomeOtherTable());
    IEnumerable<SomeOtherTable> stackOtherTable = stackOfOtherTable;

    ShowTableDef(arrayOfSomeTable);
    ShowTableDef(listOfSomeTable);
    ShowTableDef(stackOfOtherTable);
}

public void ShowTableDef<T>(IEnumerable<T> objectToLog) where T : ITable
{
    foreach (ITable tbl in objectToLog)
    {
        Console.WriteLine(tbl.GetTableDefinition());
    }
}

public interface ITable { string GetTableDefinition(); }

public class SomeTable : ITable
{
    public string GetTableDefinition() { return "foo"; }
}

public class SomeOtherTable : ITable
{
    public string GetTableDefinition() { return "bar"; }
}