标签: generic-variance

为什么我可以抛弃IList <T>的不变性?

目前,我正准备为我的同事介绍C#中新的通用差异功能.为了简化故事,我写了以下几行:

IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = formsList;
Run Code Online (Sandbox Code Playgroud)

是的,这当然是不可能的,因为IList(Of T)是不变的(至少我的想法).编译器告诉我:

无法隐式转换 System.Collections.Generic.IList<System.Windows.Forms.Form>System.Collections.Generic.IList<System.Windows.Forms.Control>.存在显式转换(您是否错过了演员?)

嗯,这是否意味着我可以强制进行显式转换?我刚尝试过:

IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = (IList<Control>)formsList;
Run Code Online (Sandbox Code Playgroud)

并且...它编译!这是否意味着我可以抛弃不变性? - 至少编译器没问题,但我只是将前编译时错误转为运行时错误:

Unable to cast object of type 'System.Collections.Generic.List`1[System.Windows.Forms.Form]' to type 'System.Collections.Generic.IList`1[System.Windows.Forms.Control]'.

我的问题:为什么我可以将IList<T>(或我的实验的任何其他不变界面)的不变性抛弃了?我是否真的抛弃了不变性,或者在这里发生了什么样的转换(因为IList(Of Form)并且IList(Of Control)完全不相关)?这是C#的一个黑暗角落,我不知道?

c# type-conversion generic-variance c#-4.0

5
推荐指数
1
解决办法
673
查看次数

IDictionary <K,IEnumerable/IList/ICollection <V >>上的单一扩展方法

我正在尝试编写一个扩展方法,该方法将转换IDictionary<K, S<V>>保存任何类型的collection/sequence(S<V>),ILookup<K, V>在这些情况下,这是更合适的数据结构.这意味着我希望我的扩展能够在不同的S类型和接口上工作:

  • IDictionary<K, IEnumerable<V>>
  • IDictionary<K, ICollection<V>>
  • IDictionary<K, List<V>>

理想情况下,我不想为每种可能的集合类型编写单独的实现,并且我希望类型推断能够完成它的工作.

我试过的是:

public static ILookup<TKey, TValue>ToLookup<TKey, TCollection, TValue>(
    this IDictionary<TKey, TCollection> dictionary)
        where TCollection : IEnumerable<TValue>
Run Code Online (Sandbox Code Playgroud)

但它没有TValue参数列表,所以类型推断无法弄明白 - 我得到"方法ToLookup的类型参数不能从用法推断".

是否有可能以某种方式以某种方式工作,而不是在方法中添加假的TValue参数?

预期用途的示例

我希望所有上述调用都成为可能,并导致调用我的单个扩展方法:

var dictOfIEnumerables = new Dictionary<int, IEnumerable<int>>();
var lookupFromIEnumerables = dictOfIEnumerables.ToLookup();

var dictOfICollections = new Dictionary<int, ICollection<int>>();
var lookupFromICollections = dictOfICollections.ToLookup();

var dictOfLists = new Dictionary<int, List<int>>();
var lookupFromLists = dictOfLists.ToLookup();
Run Code Online (Sandbox Code Playgroud)

c# generics extension-methods covariance generic-variance

5
推荐指数
1
解决办法
326
查看次数

为什么类型下限会改变方差位置?

Scala语言规范(关于方差注释的第 4.5 节,第 44 页)

  • 类型参数的方差位置与封闭类型参数子句的方差位置相反。
  • 类型声明或类型参数下界的方差位置与类型声明或参数的方差位置相反。

使用上面的第一点,很容易看出(至少在形式上)

trait Covariant[+A] {
  def problematic[B <: A](x : B)
}
Run Code Online (Sandbox Code Playgroud)

产生错误消息

error: covariant type A occurs in contravariant position in type >: Nothing <: A of type B
       def problematic[B <: A](x : B)
Run Code Online (Sandbox Code Playgroud)

使用第一点和第二点很容易看出

trait Contravariant[-A] {
  def problematic[B >: A](x : B)
}
Run Code Online (Sandbox Code Playgroud)

产生错误消息

error: contravariant type A occurs in covariant position in type >: A <: Any of type B
             def problematic[B >: A](x : B)
Run Code Online (Sandbox Code Playgroud)

正如我所提到的,很容易从形式上(即遵循方差注释的规则)看出这些错误发生的原因。然而,我无法举出一个例子来说明这些限制的必要性。相反,很容易举出示例来说明为什么方法参数应该更改方差位置,请参见 …

scala generic-variance

5
推荐指数
1
解决办法
250
查看次数

使用扩展方法规避方差检查

这不会编译:

class MyClass[+A] {
  def myMethod(a: A): A = a
}
//error: covariant type A occurs in contravariant position in type A of value a
Run Code Online (Sandbox Code Playgroud)

好吧,很公平。但这确实可以编译:

class MyClass[+A]

implicit class MyImplicitClass[A](mc: MyClass[A]) {
  def myMethod(a: A): A = a
}
Run Code Online (Sandbox Code Playgroud)

这使我们能够规避方差检查给我们带来的任何问题:

class MyClass[+A] {
  def myMethod[B >: A](b: B): B = b  //B >: A => B
}

implicit class MyImplicitClass[A](mc: MyClass[A]) {
  def myExtensionMethod(a: A): A = mc.myMethod(a)  //A => A!!
}

val foo = new MyClass[String]
//foo: MyClass[String] …
Run Code Online (Sandbox Code Playgroud)

scala covariance generic-variance

5
推荐指数
1
解决办法
216
查看次数

Kotlin 中的使用站点差异

open class A
class B: A()

fun <T> copy(src: MutableList<T>, dst: MutableList<T>) {
    for (i in 0 until src.size) {
        dst.add(i, src[i])
    }
}
Run Code Online (Sandbox Code Playgroud)

对于上面提到的代码,我理解copy function期望两个类型参数的类型完全相同。稍微修改copy(src: MutableList<T>, dst: MutableList<in T>)一下in关键字,我是说它src 必须是完全类型,T但目的地可以是Ttype T任何超类型

对于上述修改后的代码,我可以调用如下方法,

fun main(args: Array<String>) {
    val l1 = mutableListOf(B(), B())
    val l2 = mutableListOf<A>()
    copy(l1, l2)
} // main
Run Code Online (Sandbox Code Playgroud)

copy(l1, l2)如果我in从目的地删除(理解),上述方法不起作用。

我的问题是,如果更新函数参数src以接受out列表的投影,我可以毫无错误地调用该函数。例如

fun …
Run Code Online (Sandbox Code Playgroud)

generics covariance contravariance generic-variance kotlin

3
推荐指数
1
解决办法
167
查看次数

Kotlin:如果 E 是实现接口 I 的枚举类,则从返回类型为 Array&lt;I&gt; 的函数中返回 Array&lt;E&gt;

最近我遇到了一个问题,我有一个函数必须返回一个Is数组,以 enum 的所有值的形式EE实现 interface I,我想到的每个代码编译器都抱怨类型不匹配:

Error:(x, x) Kotlin: Type mismatch: inferred type is Array<E> but Array<I> was expected
Run Code Online (Sandbox Code Playgroud)

一个最小的例子:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return E.values()
    }
Run Code Online (Sandbox Code Playgroud)

当尝试分配E.values()给类型的变量时会发生这种情况,Array<I> 我很确定这应该是可能的,因为E实现了I.

我在测试时想到的另一件事是,像这样使用时它工作得很好:

    interface I {}
    enum class E: I {
        A, B, C;
    }
    fun getMoreInterfaces(): Array<I> {
        return arrayOf(E.A, E.B, E.C)
    }
Run Code Online (Sandbox Code Playgroud)

我在这个主题上做了很多搜索,但没有运气(也许我选择了错误的描述方式?)

enums type-mismatch generic-variance kotlin

3
推荐指数
1
解决办法
4798
查看次数

C#代表引擎问题

在SO中阅读以下问题后,我正在研究代理方差:Delegate.CreateDelegate()和泛型:绑定到目标方法的错误

我在Barry kelly找到了一段非常好的代码, 网址是https://www.blogger.com/comment.g?blogID=8184237816669520763&postID=2109708553230166434

这是(以加糖形式:-)

using System;

namespace ConsoleApplication4
{
    internal class Base
    {
    }

    internal class Derived : Base
    {
    }

    internal delegate void baseClassDelegate(Base b);

    internal delegate void derivedClassDelegate(Derived d);


    internal class App
    {
        private static void Foo1(Base b)
        {
            Console.WriteLine("Foo 1");
        }

        private static void Foo2(Derived b)
        {
            Console.WriteLine("Foo 2");
        }

        private static T CastDelegate<T>(Delegate src)
            where T : class
        {
            return (T) (object) Delegate.CreateDelegate(
                                    typeof (T),
                                    src.Target,
                                    src.Method,
                                    true); // throw on fail …
Run Code Online (Sandbox Code Playgroud)

c# delegates generic-variance

2
推荐指数
1
解决办法
585
查看次数

Scala中的类类型参数.

我写一些应该很直接的东西很难,但我似乎无法正确理解语法.

我有食物的类层次结构:

Food :> Vegetable :> Bamboo
Run Code Online (Sandbox Code Playgroud)

而对于动物:

Animal :> Herbivore :> Panda
Run Code Online (Sandbox Code Playgroud)

而我正试图在动物中定义一种吃法,这样熊猫一般不能吃蔬菜,只能吃竹子.目前,我的代码如下所示:

class Food(val name : String)
class Vegetable(name: String) extends Food(name)
class Bamboo extends Vegetable("bamboo")

class Animal[F <: Food](val name : String) {
    def eat[T <: F](f : T) = println(s"$name eats some yummy ${f.name}")
}
class Herbivore[F <: Vegetable](name :String) extends Animal[Vegetable](name)
class Panda extends Herbivore[Bamboo]("panda")
Run Code Online (Sandbox Code Playgroud)

我的麻烦是,当我制作蔬菜时,熊猫可以吃它:

(new Panda) eat (new Vegetable("potato"))
Run Code Online (Sandbox Code Playgroud)

出了点问题:(

任何帮助将非常欢迎:)

scala generic-variance

2
推荐指数
1
解决办法
73
查看次数

逆向性如何与.net核心中的Func委托一起使用

我有以下代码,我正在尝试为我的域对象编写通用验证规则.这样做我有一个问题来处理Func委托支持方差

public class Person { }
public class Employee : Person { }

internal interface IValidation<T> where T: Person  
{
     void AddValidationRule(Func<T,bool> predicateFunction);
}

internal class BaseValidation : IValidation<Person>
{
    void IValidation<Person>.RegisterValidationRules(Person person)
    {

    }
}

internal class EmployeeValidation : BaseValidation
{
    void RegisterValidation()
    {
        Func<Employee,bool> empPredicate = CheckJoiningDate;
        base.AddValidationRule(empPredicate);
    }

    bool CheckJoiningDate(Employee employee)
    {
        return employee.JoiningDate > DateTime.Now.AddDays(-1) ;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,编译器会给出一条错误消息

编译器错误在线:base.AddValidationRule(empPredicate); 参数1:无法从'System.Func <> Employee,bool>'转换为'System.Func <> Person,bool>

我曾参考过这个https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/dd465122%28v%3dvs.100%29但我仍然无法使编译器了解这里的逆变,

感谢您的帮助,让我更好地理解这一点

c# generic-variance .net-core asp.net-core-2.1

2
推荐指数
1
解决办法
217
查看次数

TypeScript 不推断矛盾的解决方法?

TypeScript 似乎无法推断逆变。下面是一个例子来说明这种不一致:

class Base { base = "I'm base" }
class Der extends Base { der = "I'm der" }

interface Getter<E> { get(): E }
interface Setter<E> { set(value: E): void }

type Test1 = Getter<Der> extends Getter<Base> ? 'Yes' : 'No' // "Yes"
type Test2 = Getter<Base> extends Getter<Der> ? 'Yes' : 'No' // "No"

type Test3 = Setter<Der> extends Setter<Base> ? 'Yes' : 'No' // "Yes"
type Test4 = Setter<Base> extends Setter<Der> ? 'Yes' : 'No' // …
Run Code Online (Sandbox Code Playgroud)

covariance contravariance generic-variance typescript

2
推荐指数
1
解决办法
588
查看次数

为什么我必须转换为类型参数而不能使用约束类型?

任何人都可以解释为什么我必须转换为T,为什么Add2不接受Bar作为参数?

class Foo<T> where T : class, IBar
{
    void Add1(IDo<T> @do) { @do.Stuff(new Bar() as T); }

    // Add2 does not compile:
    // Argument type Bar is not assignable to parameter Type T
    void Add2(IDo<T> @do) { @do.Stuff(new Bar()); } 
}

interface IBar {}

class Bar : IBar {}

interface IDo<in T> {
    void Stuff(T bar);
}
Run Code Online (Sandbox Code Playgroud)

c# generics casting generic-variance

1
推荐指数
1
解决办法
75
查看次数