Это не может точно попасть в 'grep' категорию, но я не мог продвинуться в Windows без утилиты, названной AgentRansack. Это - находящееся в gui, "находят в файлах" утилиту с поддержкой regex. Это очень просто, чтобы щелкнуть правой кнопкой по папке, совершить нападки, "роются.." и найдите файлы, содержащие, что Вы ищете. Чрезвычайно быстро также.
.NET не имеет ковариации и противоречивости (пока).
То, что B является производным от A, не означает, что List
является производным от List < A>
. Это не так. Это два совершенно разных типа.
.NET 4.0 будет иметь ограниченную ковариацию и контр-дисперсию.
Это проблема ковариантности, и это не так просто, как кажется на первый взгляд. В C # 4 для этого есть некоторая поддержка.
Чтобы понять проблемы, представьте в вашем случае, что это приведение действительно сработает. Теперь у вас есть List
, который, например, также имеет метод Add
. Однако аргументом для фактического Add
должен быть Customer
, так что это явно нарушает реализацию;
C # (в настоящее время) не поддерживает дисперсию для универсальных типов.
Однако, если вы используете C # 3.0, вы можете сделать это:
FillSmartGrid( customers.Cast<object>() );
Это потому, что список класса не может быть преобразован в список базового класса. Это сознательное решение сделать язык безопасным. Этот вопрос задают часто.
Вот мой стандартный ответ о том, как обойти проблему:
List<A> listOfA = new List<C>().ConvertAll(x => (A)x);
или:
List<A> listOfA = new List<C>().Cast<A>().ToList();
Также здесь действительно хорошее объяснение от самого Эрика Липперта, один из главных архитекторов в команде C #.
Это было до тошноты освещено во многих других ответах. Краткий ответ таков:
Считайте, что у меня есть эти переменные:
List<Customer> customers = new List<Customer>(); //ok, seems fair
List<object> objects = new List<object>(); // again, everything's fine
Вот где он перестает компилироваться:
objects = customers; // sounds OK, since a Customer is an object, right?
objects.Add("foo");
Теперь это имеет смысл?
C # 4.0 представит ограниченные возможности делать то, что вы попытки, хотя возможность выполнить точно , как вы описываете (назначить List
для List
, не будет разрешено для того же рассуждения я изложил выше). См. блог Эрика Липперта для получения дополнительной информации и исправления некоторой дезинформации, которая распространяется в сети.
Чтобы ответить на ваш комментарий выше, нет причин, по которым вы можете '
Вместо передачи List, который не работает по указанным выше причинам, не могли бы вы просто передать просто ссылку на объект, а затем получить тип списка, вроде как ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
class Customer {
public int id;
public string name;
}
class Monkey {
public void AcceptsObject(object list) {
if (list is List<Customer>) {
List<Customer> customerlist = list as List<Customer>;
foreach (Customer c in customerlist) {
Console.WriteLine(c.name);
}
}
}
}
class Program {
static void Main(string[] args) {
Monkey monkey = new Monkey();
List<Customer> customers = new List<Customer> { new Customer() { id = 1, name = "Fred" } };
monkey.AcceptsObject(customers);
Console.ReadLine();
}
}
}
Почему параметр не может иметь тип IList?
public void FillSmartGrid (IList items)
Я согласен с ответом Уинстона Смита.
Я просто хотел указать в качестве альтернативы (хотя, возможно, это не лучший способ справиться с ситуацией), что while List
не является производным от List
, Customer [] действительно является производным от Object [].
Следовательно, можно сделать следующее:
{
List<Customer> customers = new List<Customer>();
// ...
FillSmartGrid(customers.ToArray());
// ...
}
public void FillSmartGrid(object[] items)
{
}
Конечно, Обратной стороной является то, что вы создаете объект массива только для того, чтобы передать его этой функции.