我有一个班级
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。
答案 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;
double
和int
只是不要一起去!
答案 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"; }
}