我知道可以将一个项目列表从一种类型转换为另一种类型(假设您的对象有一个公共静态显式运算符方法来执行转换),一次一个:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Run Code Online (Sandbox Code Playgroud)
但是不可能一次投出整个列表吗?例如,
ListOfY = (List<Y>)ListOfX;
Run Code Online (Sandbox Code Playgroud) ReSharper建议我通过改变这个来改变类型参数T contravariant:
interface IBusinessValidator<T> where T: IEntity
{
void Validate(T entity);
}
Run Code Online (Sandbox Code Playgroud)
进入:
interface IBusinessValidator<in T> where T: IEntity
{
void Validate(T entity);
}
Run Code Online (Sandbox Code Playgroud)
那么<T>
和之间有什么不同<in T>
?这里逆变的目的是什么?
让说我有IEntity
,Entity
,User
和Account
实体.假设双方User
和Account
有Name
需要验证属性.
如何在此示例中应用逆变的用法?
我正在浏览 dart 文档,在那里我遇到了这段代码和这个术语
covariant
。我浏览了一些文档,但我不明白function
其中的内容。详细解释的答案总是值得赞赏的。
class Animal {
void chase(Animal x) { ... }
}
class Mouse extends Animal { ... }
class Cat extends Animal {
@override
void chase(covariant Mouse x) { ... }
}
Run Code Online (Sandbox Code Playgroud) 协方差(大致)是在使用它们的复杂类型中镜像 "简单"类型的继承的能力.
例如,我们总是可以将一个实例Cat
视为一个实例Animal
.如果ComplexType是协变ComplexType<Cat>
的ComplexType<Animal>
,则可以将A 视为a .
我想知道:协方差的"类型"是什么,它们与C#有什么关系(它们是否受支持?)
代码示例会有所帮助.
例如,一种类型是返回类型协方差,由Java支持,但不支持C#.
我希望有功能编程印章的人也可以加入!
我在使用泛型时理解多态如何工作时遇到了问题.举个例子,我定义了以下程序:
public interface IMyInterface
{
void MyMethod();
}
public class MyClass : IMyInterface
{
public void MyMethod()
{
}
}
public class MyContainer<T> where T : IMyInterface
{
public IList<T> Contents;
}
Run Code Online (Sandbox Code Playgroud)
我可以这样做,这很好用:
MyContainer<MyClass> container = new MyContainer<MyClass>();
container.Contents.Add(new MyClass());
Run Code Online (Sandbox Code Playgroud)
我有很多实现MyInterface的类.我想编写一个可以接受所有MyContainer对象的方法:
public void CallAllMethodsInContainer(MyContainer<IMyInterface> container)
{
foreach (IMyInterface myClass in container.Contents)
{
myClass.MyMethod();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我想称之为这种方法.
MyContainer<MyClass> container = new MyContainer<MyClass>();
container.Contents.Add(new MyClass());
this.CallAllMethodsInContainer(container);
Run Code Online (Sandbox Code Playgroud)
那没用.当然,因为MyClass实现了IMyInterface,我应该能够实现它吗?
MyContainer<IMyInterface> newContainer = (MyContainer<IMyInterface>)container;
Run Code Online (Sandbox Code Playgroud)
那也行不通.我绝对可以将一个普通的MyClass转换为IMyInterface:
MyClass newClass = new MyClass();
IMyInterface myInterface = (IMyInterface)newClass;
Run Code Online (Sandbox Code Playgroud)
所以,至少我没有完全误解这一点.我不确定我是如何编写一个接受符合相同接口的类的泛型集合的方法. …
在阅读维基百科关于协方差和逆变的文章的一部分时,我遇到了以下粗体句:
首先考虑数组类型构造函数:从
Animal
我们可以创建类型的类型Animal[]
("动物数组").我们应该把它视为
- 协变:a
Cat[]
是aAnimal[]
- 逆变:a
Animal[]
是aCat[]
- 或两者(不变)?
如果我们希望避免类型错误,并且数组支持读取和写入元素,那么只有第三种选择是安全的.显然,不是每一个都
Animal[]
可以被视为一个Cat[]
,因为从阵列读取的客户端将期望一个Cat,但是Animal[]
可能包含例如aDog
.所以逆变规则并不安全.相反,一个
Cat[]
不能被视为一个Animal[]
.它总是可以Dog
放入一个Animal[]
.对于协变数组,这不能保证是安全的,因为后备存储实际上可能是一组猫.所以协变规则也不安全 - 数组构造函数应该是不变的.请注意,这只是可变数组的问题; 协变规则对于不可变(只读)数组是安全的.
我理解这个概念; 我只是想要一个如何在C#中"无法保证安全" 的例子.
在接口方面,我不清楚C#中Covariance的概念.严格基于我下面的例子,这是协方差的一个例子,请描述原因或原因.
class Program
{
static void Main()
{
ICarInterface car = new Car();
}
}
interface ICarInterface
{
void Start();
}
class Car : ICarInterface
{
public void Start()
{
}
}
Run Code Online (Sandbox Code Playgroud) 我看到了以下用法:
interface IGobbler<in T> {
void gobble(T t);
}
Run Code Online (Sandbox Code Playgroud)
我不明白in的用法是什么.是否有关系REF,出来?
刚刚注意到这不起作用:
var dict = new Dictionary<int, XElement>();
XContainer element;
//...
if (dict.TryGetValue(idx, out element)) { //...
Run Code Online (Sandbox Code Playgroud)
然后我尝试了这个:
class A { }
class B : A { }
class Program {
static void Main() {
A a;
a = Ret(); // no error, ok
Ref(ref a); // compiler error, ok...
Out(out a); // compiler error, lolwut?!
}
static B Ret() { return null; }
static void Ref(ref B b) { }
static void Out(out B b) { b = null; } …
Run Code Online (Sandbox Code Playgroud) 如果我有 :
public class A { public int a1;}
public class B : A { public int b1;}
void myFunc(A a)
{}
static void Main(string[] args)
{
B b = new B();
myFunc(b);
}
Run Code Online (Sandbox Code Playgroud)
在myFunc
,a
可以访问b
对象,但它只能引用(没有强制转换)到内存中的区域type A
.
这是理解的.
在协方差的 HOwever 似乎也a
可以访问b
:
正如您所看到的 - 它接受Enumerable,A
它仍然可以访问其B
类型化的对象
问题:
1)好的,幕后它是如何工作的?A
参考怎么能给我看一个larger
对象?
2)如果我想在函数中看到类中的a1
属性A
怎么办?我应该更改什么?
协方差相关:
在C#4之前,你无法传入List:无法从'System.Collections.Generic.List'转换为'System.Collections.Generic.IEnumerable'
让我们考虑一个抽象基类和一个或多个子类:
public abstract class BaseInnerClass
{
public int Id { get; set; }
}
public class ConcreteInnerClass : BaseInnerClass
{
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后,我们假设有一个通用抽象类,它具有以上抽象类类型的属性:
public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass
{
public T InnerClass { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后让我们创建一个继承自上面类的类:
public class ConcreteTestClass : GeneriAbstractTestClass<ConcreteInnerClass>
{
public string ConcreteString { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
所以现在一切都准备问一个问题;)为什么不可能这样做:
//cannot convert initializer type
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
Run Code Online (Sandbox Code Playgroud)
虽然这是允许的:
//ok
BaseInnerClass baseInner = new ConcreteInnerClass();
Run Code Online (Sandbox Code Playgroud)
这两项任务有什么区别?
我有抽象基类,如:
public abstract class CacheValueProviderBase<T> where T : ICacheItem
{
protected ConcurrentDictionary<int,T> dataList = new ConcurrentDictionary<int, T>();
public virtual void Add(T model){ // add code }
public virtual bool Remove(int id){ //remove code }
public abstract string getName();
public abstract void UpdateForceFromDataBase();
public abstract void UpdateForceFromCacheServer();
public virtual bool allowForUpdater
{
get
{
return true;
}
}
public virtual bool beforeUpdate()
{
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
我有来自这个抽象类的多个派生类.以下Slider_CacheValueProvider
类用作示例.
public class Slider_CacheValueProvider : CacheValueProviderBase<Cache_Home_Slider_Model>
{
public override string getName()
{ …
Run Code Online (Sandbox Code Playgroud) 我有这个简单的代码,它会生成一个警告:
private void MyMethod()
{
IDictionary<string, object> notNullable = new Dictionary<string, object>();
Test(notNullable);
}
private void Test(IDictionary<string, object?> nullable)
{
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译时收到此警告(尽管它确实适用于!):
由于引用类型的可为空性的差异,“Dictionary<string, object>”类型的参数不能用于“...”中“IDictionary”类型的参数“nullable”
现在我可以看到相反的问题,但是我将不可为空的参数发送到可空参数是怎么回事?只是 C# 编译器的限制,或者可能是一个错误?