質問

I have 2 public interfaces used by a client

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

public interface IItem {
    string Name { get; set; }
}

The idea is for the client to access the data through this object :

IASet<IItem> aset = GetIt();
foreach(IItem i in aset.Collection)
    Console.WriteLine(i.Name);

The concrete implementation is as follow :

private class ASet : IASet<OneItem>{
    public HashSet<OneItem> Collection { get; set; }
}
private class OneItem : IItem{
    public string Name { get; set; }
}

And finnaly the function generating the objects :

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;
}

Because my real code is not as simple as this one, I cannot change ASet : IASet<OneItem> to something like ASet<T> : IASet<T>

Could you please explain me why I cannot do that, and some suggestions to correct the problem ?

Thanks

役に立ちましたか?

解決

I think you should take a look at my response to this question, it explains you case Interface with generic object of the interface type

By the way I suggest you make changes to you GetIt Function like that :

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;
}

and then you need to call it like that:

  IASet<OneItem> aset = GetIt<OneItem>();
  foreach (IItem i in aset.Collection)
    Console.WriteLine(i.Name);

if you want more details you have to explain your requirement more.

他のヒント

The problem here is you are returning an instance of ASet but the return type is IASet<IItem>. The ASet type actually implements the interface IASet<OneItem>. This interface is not convertible to IASet<IItem> even though OneItem implements IITem.

This type of conversion is allowed when the type parameter on IASet is marked with out (i.e. IASet<out T>). This would identify the type parameter as covariant and allow for this type of conversion.

Unfortunately this is not possible in your scenario. The easiest way to think of out T is that T only appears in output positions on the API. In this case T is used in HashSet<T>. In that usage T appears in both input and output positions hence T can't be marked as out.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top