una trigonometricas real implicita funcion ejemplos derivar derivadas derivada derivacion deriva como calculadora c# .net generics covariance

c# - trigonometricas - derivada de una funcion real



¿Por qué no puedo asignar una Lista<Derivada> a una Lista<Base>? (5)

Definí la siguiente clase:

public abstract class AbstractPackageCall { ... }

También defino una subclase de esta clase:

class PackageCall : AbstractPackageCall { ... }

También hay varias otras subclases de AbstractPackageCall

Ahora quiero hacer la siguiente llamada:

List<AbstractPackageCall> calls = package.getCalls();

Pero siempre obtengo esta excepción:

Error 13 Cannot implicitly convert type ''System.Collections.Generic.List<Prototype_Concept_2.model.PackageCall>'' to ''System.Collections.Generic.List<Prototype_Concept_2.model.AbstractPackageCall>''

¿Cuál es el problema aquí? Este es el método Package # getCalls

internal List<PackageCall> getCalls() { return calls; }


Por qué lo que intentas no funciona

Le está pidiendo al compilador que trate una List<PackageCall> como una List<AbstractPackageCall> , que no es así. Otra cosa es que cada una de esas instancias de PackageCall sea ​​de hecho una AbstractPackageCall .

¿Qué funcionaría en su lugar?

var calls = package.getCalls().Cast<AbstractPackageCall>().ToList();

Por qué lo que intentas nunca se le permitirá trabajar

Aunque cada elemento dentro del valor de retorno de package.getCalls() proviene de AbstractPackageCall , no podemos tratar la lista completa como List<AbstractPackageCall> . Esto es lo que sucedería si pudiéramos:

var calls = package.getCalls(); // calls is List<PackageCall> List<AbstractPackageCalls> apcs = calls; // ILLEGAL, but assume we could do it apcs.Add(SomeOtherConcretePackageCall()); // BOOM!

Si pudiéramos hacer eso, entonces podríamos agregar un SomeOtherConcretePackageCall a una List<PackageCall> .


Ahora si quieres hacer la siguiente llamada:

List<PackageCall> calls = package.getCalls(); // select only AbstractPackageCall items List<AbstractPackageCall> calls = calls.Select(); calls.Add(new AnotherPackageCall());

Yo llamo a esto generalización.

Además, puedes usar esto más específico:

List<PackageCall> calls = package.getCalls(); // select only AnotherPackageCall items List<AnotherPackageCall> calls = calls.Select(); calls.Add(new AnotherPackageCall());

Implemente esto usando el método de extensión:

public static class AbstractPackageCallHelper { public static List<U> Select(this List<T> source) where T : AbstractPackageCall where U : T { List<U> target = new List<U>(); foreach(var element in source) { if (element is U) { target.Add((U)element); } } return target; } }


La forma más simple de entender por qué esto no está permitido es el siguiente ejemplo:

abstract class Fruit { } class Apple : Fruit { } class Banana : Fruit { } // This should intuitively compile right? Cause an Apple is Fruit. List<Fruit> fruits = new List<Apple>(); // But what if I do this? Adding a Banana to a list of Apples fruits.Add(new Banana());

La última declaración arruinaría el tipo de seguridad de .NET.

Sin embargo, las matrices permiten esto:

Fruit[] fruits = new Apple[10]; // This is perfectly fine

Sin embargo, poner un Banana en las fruits todavía rompería la seguridad del tipo, así que .NET tiene que hacer un control de tipo en cada inserción del arreglo y lanzar una excepción si no es realmente un Apple . Esto es potencialmente un golpe de rendimiento (pequeño), pero esto se puede eludir mediante la creación de un envoltorio de struct alrededor de cualquier tipo ya que esta comprobación no ocurre para los tipos de valor (porque no pueden heredar de nada). Al principio, no entendí por qué se tomó esta decisión, pero se encontrará con frecuencia por qué esto puede ser útil. El más común es String.Format , que toma params object[] y cualquier matriz se puede pasar a esto.

Sin embargo, en .NET 4, hay una covarianza / contravarianza segura, que te permite realizar asignaciones como estas, pero solo si son probadamente seguras. ¿Qué es probadamente seguro?

IEnumerable<Fruit> fruits = new List<Apple>();

Lo anterior funciona en .NET 4, porque IEnumerable<T> convirtió en IEnumerable<out T> . La out significa que T solo puede salir de las fruits y que no existe ningún método en IEnumerable<out T> que tome T como parámetro, por lo que nunca se puede pasar incorrectamente un Banana a IEnumerable<Fruit> .

La contradicción es muy parecida, pero siempre me olvido de los detalles exactos. Como era de esperar, ahora existe la palabra clave in en los parámetros de tipo.


No puede realizar esta conversión, porque una List<AbstractPackageCall> puede contener cualquier cosa que se derive de AbstractPackageCall , mientras que una List<PackageCall> no puede; solo puede contener elementos que se derivan de PackageCall .

Considere si este elenco fue permitido:

class AnotherPackageCall : AbstractPackageCall { } // ... List<AbstractPackageCall> calls = package.getCalls(); calls.Add(new AnotherPackageCall());

Acaba de agregar un AnotherPackageCall en una List<PackageCall> - ¡pero AnotherPackageCall no se deriva de PackageCall ! Es por eso que esta conversión no está permitida.


Porque List<PackageCall> no hereda de List<AbstractPackageCall> . Puede usar el método de extensión Cast<>() , como:

var calls = package.getCalls().Cast<AbstractPackageCall>();