C# 为什么我不能将对象强制转换到它正在实现的接口?

C# 为什么我不能将对象强制转换到它正在实现的接口?,c#,generics,collections,interface,variance,C#,Generics,Collections,Interface,Variance,我有两个客户端使用的公共接口 public interface IASet<T> where T : IItem { HashSet<T> Collection { get; set; } } public interface IItem { string Name { get; set; } } 公共接口iSet,其中T:IItem{ HashSet集合{get;set;} } 公共接口项{ 字符串名称{get;set;} } 其目的是让客户机通过

我有两个客户端使用的公共接口

public interface IASet<T> where T : IItem {
    HashSet<T> Collection { get; set; }
}

public interface IItem {
    string Name { get; set; }
}
公共接口iSet,其中T:IItem{
HashSet集合{get;set;}
}
公共接口项{
字符串名称{get;set;}
}
其目的是让客户机通过此对象访问数据:

IASet<IItem> aset = GetIt();
foreach(IItem i in aset.Collection)
    Console.WriteLine(i.Name);
IASet aset=GetIt();
foreach(aset.集合中的项目i)
控制台写入线(即名称);
具体实施情况如下:

private class ASet : IASet<OneItem>{
    public HashSet<OneItem> Collection { get; set; }
}
private class OneItem : IItem{
    public string Name { get; set; }
}
专用类ASet:IASet{
公共哈希集集合{get;set;}
}
私有类1项目:项目{
公共字符串名称{get;set;}
}
最后是生成对象的函数:

public static IASet<IItem> GetIt()
{
    ASet a = new ASet();
    a.Collection = new HashSet<OneItem>();
    a.Collection.Add(new OneItem() { Name = "one" });
    a.Collection.Add(new OneItem() { Name = "two" });
    //for test :
    foreach (IItem i in a.Collection)
    {
        Console.WriteLine(i.Name);
    }

    /*Error 1   Cannot implicitly convert type 'ConsoleApplication2.Program.ASet'
     * to 'ConsoleApplication2.IASet<ConsoleApplication2.IItem>'. An explicit
     * conversion exists (are you missing a cast?)
    */
    //return a;


    /*Unable to cast object of type 'ASet' to type
     * 'ConsoleApplication2.IASet`1[ConsoleApplication2.IItem]'.
     */
    return (IASet<IItem>)a;
}
publicstaticiaset GetIt()
{
ASet a=新ASet();
a、 Collection=newhashset();
a、 Add(newoneitem(){Name=“one”});
a、 Add(newoneitem(){Name=“two”});
//对于测试:
foreach(集合中的项目i)
{
控制台写入线(即名称);
}
/*错误1无法隐式转换类型“ConsoleApplication2.Program.ASet”
*到“ConsoleApplication2.IASet”。一个显式
*存在转换(您是否缺少演员阵容?)
*/
//返回a;
/*无法将类型为“ASet”的对象强制转换为类型
*'ConsoleApplication2.iSet'1[ConsoleApplication2.IItem]'。
*/
返回(IASet)a;
}
因为我真正的代码并不像这个那么简单,所以我不能将
ASet:IASet
更改为类似
ASet:IASet

你能给我解释一下为什么我不能这样做,以及一些纠正问题的建议吗


谢谢

这里的问题是您正在返回一个
ASet
的实例,但是返回类型是
IASet
ASet
类型实际上实现了接口
IASet
。即使
OneItem
实现了
IITem
,此接口也不能转换为
IASet

IASet
上的类型参数标记为
out
(即
IASet
)时,允许进行这种类型的转换。这将把类型参数标识为协变的,并允许这种类型的转换


不幸的是,这在您的场景中是不可能的。考虑
out T
最简单的方法是
T
仅出现在API上的输出位置。在这种情况下,
T
用于
HashSet
。在这种情况下,
T
同时出现在输入和输出位置,因此
T
不能标记为
out

我想你应该看看我对这个问题的回答,它解释了你的情况

顺便说一下,我建议您对GetIt函数进行如下更改:

public static IASet<T> GetIt<T>() 
  where T : IItem
{
  ASet a = new ASet();
  a.Collection = new HashSet<OneItem>();
  a.Collection.Add(new OneItem() { Name = "one" });
  a.Collection.Add(new OneItem() { Name = "two" });
  //for test :
  foreach (var i in a.Collection)
  {
    Console.WriteLine(i.Name);
  }

  /*Error 1   Cannot implicitly convert type 'ConsoleApplication2.Program.ASet'
   * to 'ConsoleApplication2.IASet<ConsoleApplication2.IItem>'. An explicit
   * conversion exists (are you missing a cast?)
  */
  //return a;


  /*Unable to cast object of type 'ASet' to type
   * 'ConsoleApplication2.IASet`1[ConsoleApplication2.IItem]'.
   */
  return (IASet<T>)a;
}
publicstaticiaset GetIt()
T:项目在哪里
{
ASet a=新ASet();
a、 Collection=newhashset();
a、 Add(newoneitem(){Name=“one”});
a、 Add(newoneitem(){Name=“two”});
//对于测试:
foreach(集合中的变量i)
{
控制台写入线(即名称);
}
/*错误1无法隐式转换类型“ConsoleApplication2.Program.ASet”
*到“ConsoleApplication2.IASet”。一个显式
*存在转换(您是否缺少演员阵容?)
*/
//返回a;
/*无法将类型为“ASet”的对象强制转换为类型
*'ConsoleApplication2.iSet'1[ConsoleApplication2.IItem]'。
*/
返回(IASet)a;
}
然后你需要这样称呼它:

  IASet<OneItem> aset = GetIt<OneItem>();
  foreach (IItem i in aset.Collection)
    Console.WriteLine(i.Name);
IASet aset=GetIt();
foreach(aset.集合中的项目i)
控制台写入线(即名称);

如果你想要更多的细节,你必须解释你的需求。

因为iSet上的
T
是不变的。它是这样声明的,
IASet
,它会起作用-但是你不能这样做,因为HashSet不会接受它。我相信只有当
IASet
的泛型类型被定义为
out
模板参数时,它才会起作用。请参见,没有任何内容阻止某人向集合中的集合添加不同类别的
IItem
对象。