C# 当类型从同一接口派生时合并可观察序列
我有一种情况,我想合并两个可观测序列。该序列由类似代码示例中的Ex1的消息组成。我不明白为什么它不能编译,当Ex2按照预期编译和运行时 谁能给我解释一下吗C# 当类型从同一接口派生时合并可观察序列,c#,.net,system.reactive,C#,.net,System.reactive,我有一种情况,我想合并两个可观测序列。该序列由类似代码示例中的Ex1的消息组成。我不明白为什么它不能编译,当Ex2按照预期编译和运行时 谁能给我解释一下吗 class Message<T> where T : IFoo {} interface IFoo {} class Foo : IFoo {} class Bar : IFoo {} class Program { static void Ex1() { var o1 = Observable.
class Message<T> where T : IFoo {}
interface IFoo {}
class Foo : IFoo {}
class Bar : IFoo {}
class Program
{
static void Ex1()
{
var o1 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => new Message<Foo>());
var o2 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => new Message<Bar>());
o1.Merge<Message<IFoo>>(o2).Subscribe(Console.WriteLine);
Console.ReadKey();
}
static void Ex2()
{
var o1 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => new Foo());
var o2 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => new Bar());
o1.Merge<IFoo>(o2).Subscribe(Console.WriteLine);
Console.ReadKey();
}
}
类消息,其中T:IFoo{}
接口IFoo{}
类Foo:IFoo{}
类栏:IFoo{}
班级计划
{
静态void Ex1()
{
var o1=Observable.Interval(TimeSpan.fromMillicles(200))。选择(x=>newmessage());
var o2=可观察的.Interval(TimeSpan.frommilluses(200)).Select(x=>newmessage());
o1.合并(o2).订阅(控制台.写入线);
Console.ReadKey();
}
静态void Ex2()
{
var o1=Observable.Interval(TimeSpan.frommissions(200)).Select(x=>newfoo());
var o2=可观察的.Interval(TimeSpan.fromMilliconds(200)).Select(x=>newbar());
o1.合并(o2).订阅(控制台.写入线);
Console.ReadKey();
}
}
Visual Studio 2017使用.Net Framework 4.6.1时出错:
Error CS1929 'IObservable<Message<Foo>>' does not contain a definition for 'Merge' and the best extension method overload 'Observable.Merge<Message<IFoo>>(IObservable<IObservable<Message<IFoo>>>, int)' requires a receiver of type 'IObservable<IObservable<Message<IFoo>>>'
Error CS1929'IObservable'不包含'Merge'的定义,而最佳扩展方法重载'Observable.Merge(IObservable,int)'需要'IObservable'类型的接收器
非常感谢 我们将从第二种方法的工作原理开始 第二种方法创建类型为
Foo
和Bar
的两个集合。但是在Merge
方法中,要使用的类型显式是接口IFoo
。这告诉方法这是要存储在新集合中的对象类型:IEnumerable
。集合接受类型为IFoo
的项,并且由于Foo
和Bar
都从接口继承,因此它们被集合接受。如果要从Merge
方法中删除类型参数,或显式指定Foo
或Bar
作为类型,则会出现与第一个方法相同的错误
那么第一种方法呢
第一个集合的类型为Message
。此消息的一般类型为Foo
。请注意,这与Message
不同,因为类型显式地是Foo
,而不是它的超类或接口。类似地,消息
的通用类型为条
,而不是IFoo
当编译器使用带有两个集合的Merge
方法时(其中一个是Message
和Message
),它知道这两个消息的泛型类型不同(一个Foo
是一个IFoo
,Bar
是一个IFoo
,但是一个Foo
不是一个Bar
,反之亦然)。因此编译器给出了一个错误,表示它需要一个相关类型的集合(需要一个类型为“IObservable”的接收器)
还有最后一件事需要注意
消息
类的定义是类消息,其中T:IFoo{}
。所有where
子句的意思是T
必须是IFoo
,就是这样。这并不意味着消息是消息
。你可以从Foo
转换为IFoo
,这是第二种方法中发生的事情,但它们不一样。仅仅因为Foo
源自IFoo
它并不意味着Message
源自Message
-,它不属于,因此您不能像以前那样强制转换它。这同样适用于Bar
和IBar
让我们看看原因
让我们使用列表
,而不是按照消息
进行思考。我现在有以下代码:
var foos = new List<Foo>();
foos.Add(new Foo());
foos.Add(new Foo());
毕竟,我对ifoos
的引用属于List
类型,Bar
源于IFoo
,因此这是完全有效的代码
但是ifoos
只是对List
的强制转换,强制转换对象不会改变其底层类型。List
只能接受类型为Foo
(或派生自Foo
)的元素。现在,考虑到对编译器的神奇更改,我们已经创建了一种情况,即它可以接受Bar
轰!运行时错误
这就是为什么cast(列表)foos
失败的原因。这就是为什么cast(消息)消息在您的问题中也失败的原因。除了这里的其他答案之外:
interface IMessage<out T> where T : IFoo { }
class Message<T> : IMessage<T> where T:IFoo { }
interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }
class Program
{
static void Ex1()
{
var o1 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => (IMessage<IFoo>)new Message<Foo>());
var o2 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => (IMessage<IFoo>)new Message<Bar>());
o1.Merge(o2).Subscribe(Console.WriteLine);
Console.ReadKey();
}
static void Main(string[] args)
{
Ex1();
}
}
接口IMessage,其中T:IFoo{}
类消息:IMessage,其中T:IFoo{}
接口IFoo{}
类Foo:IFoo{}
类栏:IFoo{}
班级计划
{
静态void Ex1()
{
var o1=可观察的.Interval(TimeSpan.frommilluses(200)).Select(x=>(IMessage)newmessage());
var o2=可观察的.Interval(TimeSpan.frommilluses(200))。选择(x=>(IMessage)new Message());
o1.合并(o2).订阅(控制台.写入线);
Console.ReadKey();
}
静态void Main(字符串[]参数)
{
Ex1();
}
}
仅仅因为Foo
源于IFoo
并不意味着Message
源于Message
-它不是-所以你不能像你那样施放它。同样的情况也适用于Bar
和IBar
。你问得很好。你给出了一个很好的例子,说明了你的想法工作正常,有什么不正常,还有一条清晰的错误消息。我印象深刻。你有更具体的情况需要帮助吗?非常感谢你的出色回答。这个例子让一切都非常清楚。我需要的是一个IMessage界面!感谢你花时间回复。我接受了Enigmativity的回答,因为他的excel四旬斋的例子。很高兴你能整理好。我必须仔细阅读协方差和逆方差
ifoos.Add(new Bar());
interface IMessage<out T> where T : IFoo { }
class Message<T> : IMessage<T> where T:IFoo { }
interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }
class Program
{
static void Ex1()
{
var o1 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => (IMessage<IFoo>)new Message<Foo>());
var o2 = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => (IMessage<IFoo>)new Message<Bar>());
o1.Merge(o2).Subscribe(Console.WriteLine);
Console.ReadKey();
}
static void Main(string[] args)
{
Ex1();
}
}