.NET Framework 3.5では、.NETFramework4.0のようにジェネリック共分散out
で使用するパラメーターがありません。
非ジェネリックバージョンのIPlate
(この場合は名前を付けますIPlateNG
)を使用して、回避策を試すことができます。
.NET Framework 4.0の次の例を検討してください(要点を示すために拡張する必要がありました)。
using System;
using System.Collections.Generic;
public interface IWaffle { string Eat(); }
// on C# 4.0 you just put the "out" to mark the covariance (and that is it)
public interface IPlate<out T> where T : IWaffle { T GetMyWaffle(); }
public class BelgiumWaffle : IWaffle {
public string Eat() { return "Eating a Belgium Waffle"; }
public string Breakfast() { return "Breakfasting a Belgium Waffle"; }
}
public class FalafelWaffle : IWaffle {
public string Eat() { return "Eating a Falafel Waffle"; }
public string Dinner() { return "Having dinner with a Falafel Waffle"; }
}
public class HugePlate : IPlate<BelgiumWaffle> {
public BelgiumWaffle GetMyWaffle() { return new BelgiumWaffle(); }
}
public class SmallPlate : IPlate<FalafelWaffle> {
public FalafelWaffle GetMyWaffle() { return new FalafelWaffle(); }
}
class Program
{
static void Main(string[] args)
{
var plates = new List<IPlate<IWaffle>>();
plates.Add(new HugePlate());
plates.Add(new SmallPlate());
IPlate<IWaffle> aPlate = plates[0];
// Anyway, when you get a member of the collection you'll get the interface, not a concrete class (obviously).
IWaffle aWaffle = aPlate.GetMyWaffle();
// So you cannot invoke any specifics (like Breakfast or Dinner)
Console.WriteLine(aWaffle.Eat());
// But if you cast the member of the collection to the specific class (or interface)
IPlate<FalafelWaffle> aSmallPlate = (SmallPlate)plates[1];
// Then you'll get the concrete class without casting again
FalafelWaffle aFalafel = aSmallPlate.GetMyWaffle();
Console.WriteLine(aFalafel.Dinner());
}
}
これで、これは.NETFramework3.5でも同じになります。
using System;
using System.Collections.Generic;
public interface IWaffle { string Eat(); }
// In this case I define this extra inteface which is non-generic
// And inside it, we need a new method equivalent to the one on the generic one
public interface IPlateNG { IWaffle GetWaffle(); }
// And make the generic one implement the non-generic one
public interface IPlate<T> : IPlateNG where T : IWaffle { T GetMyWaffle(); }
public class BelgiumWaffle : IWaffle {
public string Eat() { return "Eating a Belgium Waffle"; }
public string Breakfast() { return "Breakfasting a Belgium Waffle"; }
}
public class FalafelWaffle : IWaffle {
public string Eat() { return "Eating a Falafel Waffle"; }
public string Dinner() { return "Having dinner with a Falafel Waffle"; }
}
public class HugePlate : IPlate<BelgiumWaffle> {
// This extra method is needed due the lack of the 'out' on the definition
public IWaffle GetWaffle() { return GetMyWaffle(); }
public BelgiumWaffle GetMyWaffle() { return new BelgiumWaffle(); }
}
public class SmallPlate : IPlate<FalafelWaffle> {
// This extra method is needed due the lack of the 'out' on the definition
public IWaffle GetWaffle() { return GetMyWaffle(); }
public FalafelWaffle GetMyWaffle() { return new FalafelWaffle(); }
}
class Program
{
static void Main(string[] args)
{
// The list cannot work with the IPlate<IWaffle> anymore. So here comes IPlateNG to the rescue
var plates = new List<IPlateNG>();
plates.Add(new HugePlate());
plates.Add(new SmallPlate());
IPlateNG aPlate = plates[0];
// And instead of calling to the GetMyWaffle method we can call to the GetWaffle in this case
IWaffle aWaffle = aPlate.GetWaffle();
Console.WriteLine(aWaffle.Eat());
IPlate<FalafelWaffle> aSmallPlate = (SmallPlate)plates[1];
FalafelWaffle aFalafel = aSmallPlate.GetMyWaffle();
Console.WriteLine(aFalafel.Dinner());
}
}
この「 out」キーワードの欠如を回避するために、両方の具象クラスでGetMyWaffle
(named )の追加の非ジェネリックバージョンを作成する必要があることに注意してください。しかし、残りはかなり似ています。GetWaffle
IPlate