相关疑难解决方法(0)

协方差,不变性和逆变性用简单的英语解释?

今天,我在Java中阅读了一些关于Covariance,Contravariance(和Invariance)的文章.我阅读了英文和德文维基百科的文章,以及IBM的一些其他博客文章和文章.

但我对这些究竟是什么有点困惑?有人说,它是关于类型和子类型之间的关系,也有人说,它是关于类型转换和一些说,它是用来决定一个方法是否重载或超载.

所以我正在用简单的英语寻找一个简单的解释,它向初学者展示了Covariance和Contravariance(和Invariance).加上一点简单的例子.

java covariance contravariance

109
推荐指数
3
解决办法
3万
查看次数

无法从'方法组'转换为'System.Action <object>'错误

我创建了以下函数:

public void DelegatedCall(Action<Object> delegatedMethod)
Run Code Online (Sandbox Code Playgroud)

并定义了以下方法

public void foo1(String str) { }
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试打电话DelegateCallfoo1:

DelegatedCall(foo1);
Run Code Online (Sandbox Code Playgroud)

...我收到以下编译器错误:

Argument 1: cannot convert from 'method group' to 'System.Action<object>'

这个错误的原因是什么,我该如何纠正?不幸的是,铸造foo1Action是不是一种选择.

c# generics delegates method-group

45
推荐指数
2
解决办法
5万
查看次数

c#使用泛型的协变返回类型

下面的代码是实现协变返回类型的唯一方法吗?

public abstract class BaseApplication<T> {
    public T Employee{ get; set; }
}

public class Application : BaseApplication<ExistingEmployee> {}

public class NewApplication : BaseApplication<NewEmployee> {}
Run Code Online (Sandbox Code Playgroud)

我希望能够构造一个Application或NewApplication并让它从Employee属性返回适当的Employee类型.

var app = new Application();
var employee = app.Employee; // this should be of type ExistingEmployee
Run Code Online (Sandbox Code Playgroud)

我相信这段代码工作得很好,但是当我有几个需要相同行为的属性时,它变得非常讨厌.

有没有其他方法来实现这种行为?泛型或其他?

c# generics covariance

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

困惑拳击,铸造,隐含等

从书中:

1) int  i  =  7;
2) Object  o  =  i; //  Implicit  boxing  int-->Object
3) Object[]  a3  =  new  int[]  {  1,  2  }; //  Illegal:  no  array  conversion
Run Code Online (Sandbox Code Playgroud)

3)中的赋值是非法的,因为int不是引用类型,因此int []不能隐式转换为Object []

我不懂.在第2行)它显示int可以隐式转换为Object,在第三行中,它表示int []不可隐式转换.哇?

c#

13
推荐指数
3
解决办法
1139
查看次数

使用GenericTypeArgument在运行时更改类型

这就是我想要的

(IList<Foo>)listPropertyInfo.GetValue(item)
Run Code Online (Sandbox Code Playgroud)

这就是我获得Foo类型的方式

listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
Run Code Online (Sandbox Code Playgroud)

这是我尝试但无法成功的原因

Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
Run Code Online (Sandbox Code Playgroud)

还有这个;

((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
Run Code Online (Sandbox Code Playgroud)

这是我试图实现的方法

public static void trigger(IList<T> result)
{
    foreach (var item in result)
    {
        foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
        {
             trigger((IList<Foo>)listPropertyInfo.GetValue(item));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

c# generics

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

VS调试问题,谁能帮我解释一下这个?

一段C#代码

var isTrue = (new List<int>{1,2,3} is IEnumerable<object>);
Run Code Online (Sandbox Code Playgroud)

我得到false了代码执行的结果,但是当我将该代码复制到WATCH窗口时,结果是true.

c# debugging

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

泛型类型参数的多态性

我试图在C#中的泛型类型参数中使用多态.我已经在SO(审查其他几个问题1,2,3,4,5,6),但我仍然不清楚为什么这不工作(或者如果它甚至允许的).

背景

我有以下课程:

public class Base { }

public class Derived<T> : Base { }

public class Foo { }
Run Code Online (Sandbox Code Playgroud)

和我的派生泛型类型的实例:

var derived = new Derived<Foo>();
Run Code Online (Sandbox Code Playgroud)

基础

以下陈述都是正确的:

derived is Object

derived is Base

derived is Derived<Foo>
Run Code Online (Sandbox Code Playgroud)

问题

当我尝试将我的派生类用作另一个泛型类型中的类型参数时,我得到一些意外的行为.鉴于以下惰性实例:

var lazy = new Lazy<Derived<Foo>>();
Run Code Online (Sandbox Code Playgroud)

以下是真实的:

lazy is Lazy<Derived<Foo>>
Run Code Online (Sandbox Code Playgroud)

但是当我预期它们是真的时,这些都是错误的:

lazy is Lazy<Object>

lazy is Lazy<Base>
Run Code Online (Sandbox Code Playgroud)

为什么是这样?它们应该是真的还是我误解了仿制药是如何工作的?

.net c# generics polymorphism

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

如何将类型不变的setter添加到协变接口?

我有一个需要协变,因此,在另一个类*的覆盖可以返回一个类型的住房Shelter<Cat>,其中一个Shelter<Animal>预期.由于类在C#中不能是共变或逆变,我添加了一个接口:

public interface IShelter<out AnimalType>
{
    AnimalType Contents { get; }
}
Run Code Online (Sandbox Code Playgroud)

然而,有一个地方,IShelter(编译时类型)被分配了一个新的动物,我们确定所设置的动物将成为一只猫.起初,我以为我可以在Contents属性中添加一个集合并执行:

IShelter<Cat> shelter = new Shelter(new Cat());
shelter.Contents = new Cat();
Run Code Online (Sandbox Code Playgroud)

但是添加setter是不可能的;

Error   CS1961  Invalid variance: The type parameter 'AnimalType' must be invariantly valid on 'IShelter<AnimalType>.Contents'. 'AnimalType' is covariant.
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为否则我可以将cathelter传递给这个函数:

private static void UseShelter(IShelter<Animal> s)
{
    s.Contents = new Lion();
}
Run Code Online (Sandbox Code Playgroud)

但是,我不打算这样做.有一些方法可以将setter标记为不变量,这样UseShelter函数只能分配一个Animal,这样就可以在编译时强制执行.我需要这个的原因是因为我的代码中有一个地方知道它有一个Shelter<Cat>,并且需要将Contents属性重新分配给一个新的Cat.

到目前为止我找到的解决方法是在显式set函数中添加一个jucky运行时类型检查; Juck!

public void SetContents(object newContents)
{
    if (newContents.GetType() != typeof(AnimalType))
    {
        throw new InvalidOperationException("SetContents must be given the correct …
Run Code Online (Sandbox Code Playgroud)

c# covariance

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

C#中的协方差/逆变

我有一解释逆变/协方差的如下:

  • 委托可以具有比其方法目标更具体的参数类型.这称为逆变
  • 委托的返回类型可以比其目标方法的返回类型更不具体.这称为协方差

而且,这是一个例子.

using System;

delegate void StringAction(string s);
delegate object ObjectRetriever();

class Test
{
    static void Main()
    {
        StringAction sa = new StringAction(ActionObject);
        sa("hello");

        ObjectRetriever o = new ObjectRetriever(RetrieveString);
        object result = o();
        Console.WriteLine(result);
    }


    static string RetrieveString() {return "hello";}

    static void ActionObject(object o)
    {
        Console.WriteLine(o);
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为为了使用协方差/逆变,需要使用new如示例中所示,但我似乎得到了相同的结果sa = ActionObjecto = RetrieveString.(我用Mono测试过).

  • 那么,为什么作者new用来解释协方差/逆变?
  • 协方差/逆变思想背后的理论是什么?它只是一个花哨的名字描述object x = Everything inherit from object?这个奇怪的名字来自哪里?它的用途是什么?

c# covariance contravariance

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

无法将源类型"List <Person>"转换为IList <ISomething>

这可能是一个非常简单的问题,但对我来说没有意义.

鉴于此类:

public class Person : ICloneable {
    public object Clone()
    {
        Console.WriteLine("Hello, world");
        return new Person();
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么这样可以?

List<Person> people = new List<Person> { new Person() };

IEnumerable<ICloneable> clonables = people;
Run Code Online (Sandbox Code Playgroud)

但这不是吗?

List<Person> people = new List<Person> { new Person() };

IList<ICloneable> clonables = people;
Run Code Online (Sandbox Code Playgroud)

为什么我可以分配给IEnumerable IClonable,而不是IList ICloneable?

.net c# casting

7
推荐指数
2
解决办法
8138
查看次数