Я открыл старый проект, и когда мне захотелось его построить, я получал много ошибок, которые были очень неприятными. Я заменил компиляцию на реализацию и добавил все необходимые коды. Наконец, проект успешно строился.
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
androidTestImplementation ('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.facebook.android:facebook-android-sdk:4.+'
implementation 'com.facebook.android:account-kit-sdk:4.+'
implementation 'com.android.volley:volley:1.1.0-rc2'
implementation 'com.google.android.gms:play-services-ads:15.0.1'
testImplementation 'junit:junit:4.12'
}
Причина, по которой вы не можете сделать это, состоит в том, что список доступен для записи. Предположим, что это было законно, и посмотрите, что пойдет не так:
List<Cat> cats = new List<Cat>();
List<Animal> animals = cats; // Trouble brewing...
animals.Add(new Dog()); // hey, we just added a dog to a list of cats...
cats[0].Speak(); // Woof!
Хорошо, собака, мои кошки, это плохо.
Функция, которую вы хотите, называется «общей ковариацией», и она поддерживается в C # 4 для интерфейсов, которые, как известно, являются безопасными. IEnumerable<T>
не имеет никакого способа записи в последовательность, поэтому он безопасен.
class Animal
{
public virtual void Play(IEnumerable<Animal> animals) { }
}
class Cat : Animal
{
public override void Play(IEnumerable<Animal> animals) { }
}
class Program
{
static void Main()
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
Это будет работать на C # 4, потому что List<Cat>
конвертируется в IEnumerable<Cat>
, который можно конвертировать в IEnumerable<Animal>
. Нельзя использовать Play IEnumerable<Animal>
, чтобы добавить собаку к тому, что на самом деле является списком кошек.
Вы могли бы сделать несколько вещей. Например, элементы списка относятся к Animal
. Использование вашего кода:
cat.Play(new List<Cat>().Cast<Animal>().ToList());
Другим является создание Animal
общего, поэтому cat.Play(new List<Cat>());
будет работать.
class Animal<T>
{
public virtual void Play(List<T> animals) { }
}
class Cat : Animal<Cat>
{
public override void Play(List<Cat> cats)
{
}
}
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
Другим способом является не создание Animal
общего, а метода Play
и ограничение этого на T : Animal
class Animal
{
public virtual void Play<T>(List<T> animals) where T : Animal { }
}
class Cat : Animal
{
public override void Play<T>(List<T> animals)
{
}
}
Наконец, если вы находитесь на C # 4 и вам нужно только перечислить список и не изменять его, проверьте ответ Эрика Липперта на IEnumerable<Animal>
.
использовать метод расширения Cast ()
so:
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Play(new List<Cat>().Cast<Animal>());
}
}
Причиной этого является b / c .net 3.5 не поддерживает ковариацию, но 4.0 делает :)
Вы ищете общую ковариацию коллекции. Очевидно, что эта функция не поддерживается версией C #, которую вы используете.
Вы можете обойти это с помощью метода расширения Cast<T>()
. Имейте в виду, однако, что это создаст копию исходного списка вместо передачи оригинала как другой тип:
cat.Play((new List<Cat>()).Cast<Animal>().ToList());
Все упоминают метод литья уже. Если вы не можете обновить до 4.0, способ скрыть приведение
class Cat : Animal
{
public override void Play(List<Animal> animal)
{
Play((List<Cat>)animal);
}
public virtual void Play(List<Cat> animal)
{
}
}
Это трюк IEnumable
и IEnumarable<T>
для GetEnumerator