C#:をオーバーを返しの種類
-
20-08-2019 - |
質問
がありオーバーライドを返しの種類のC#?その場合どのような理由とは何かをお勧めいのですか?
私の場合は、インターフェースは、抽象基底クラスとその子孫ます。紹介しちゃいたいと思います(okだが、一例として!) :
public interface Animal
{
Poo Excrement { get; }
}
public class AnimalBase
{
public virtual Poo Excrement { get { return new Poo(); } }
}
public class Dog
{
// No override, just return normal poo like normal animal
}
public class Cat
{
public override RadioactivePoo Excrement { get { return new RadioActivePoo(); } }
}
RadioactivePoo
のコースを継承 Poo
.
私たいということでご利用の方 Cat
オブジェが利用可能に Excrement
物件なの Poo
入 RadioactivePoo
中には、例えば Cat
まだまだ十分とはいえませんがえる Animal
リストユーザーがユーザーが必ずしも意識や意して放射性もidコロコロいった感覚...
調査を実施しているのは、同じのコンパイラのないこと。いじゃないでしょうか不可能である。もうあなたにオススメのためのソリューションとして。
解決
どのような汎用の基本クラスについてはどうですか?
public class Poo { }
public class RadioactivePoo : Poo { }
public class BaseAnimal<PooType>
where PooType : Poo, new() {
PooType Excrement {
get { return new PooType(); }
}
}
public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }
編集:拡張メソッドとマーカーインターフェイスを使用して、新しいソリューション、...
public class Poo { }
public class RadioactivePoo : Poo { }
// just a marker interface, to get the poo type
public interface IPooProvider<PooType> { }
// Extension method to get the correct type of excrement
public static class IPooProviderExtension {
public static PooType StronglyTypedExcrement<PooType>(
this IPooProvider<PooType> iPooProvider)
where PooType : Poo {
BaseAnimal animal = iPooProvider as BaseAnimal;
if (null == animal) {
throw new InvalidArgumentException("iPooProvider must be a BaseAnimal.");
}
return (PooType)animal.Excrement;
}
}
public class BaseAnimal {
public virtual Poo Excrement {
get { return new Poo(); }
}
}
public class Dog : BaseAnimal, IPooProvider<Poo> { }
public class Cat : BaseAnimal, IPooProvider<RadioactivePoo> {
public override Poo Excrement {
get { return new RadioactivePoo(); }
}
}
class Program {
static void Main(string[] args) {
Dog dog = new Dog();
Poo dogPoo = dog.Excrement;
Cat cat = new Cat();
RadioactivePoo catPoo = cat.StronglyTypedExcrement();
}
}
この方法で犬と猫の両方が(コメントで述べて、私の最初のソリューションは、継承を保存しなかった)動物から継承します。
それは痛いですマーカーインタフェース、と明示的にクラスをマークするために必要ですが、多分これはあなたにいくつかのアイデアを与えることができる...
の SECOND編集の@Svish:私は拡張メソッドがiPooProvider
BaseAnimal
から継承しているという事実は、任意の方法で実施されていないことをexplitly表示するコードを変更しました。あなたは
他のヒント
これはを戻り値の型共分散のと呼ばれ、いくつかの人々の<のhref = "http://connect.microsoft.com/VisualStudio/feedback/にもかかわらず、一般的にはC#や.NETでサポートされていません。 ViewFeedback.aspx?FeedbackID = 90909" のrel = "nofollowをnoreferrer"> に願います。
私は何だろうと、同じシグネチャを保つが、私はこの1つはENSURE
を返すことを保証する派生クラスに追加RadioActivePoo
句を追加しています。だから、要するに、私は構文を経由して行うことはできませんどのような契約による設計を経由して行うと思います。
その他href="http://peisker.net/dotnet/covariance.htm"ではなく、それをnoreferrer">偽物をrel="nofollow
示唆
ないので多くのソリューションをこの問題は既にできているのだと思い越えることのできなかったことに問題があったか、既存のソリューション。
私は笑いのは、既存のソリューションは以下の理由から
- Paolo Tedescoの第一ソリューション: 犬-猫のない共通の基底クラスです。
- Paolo Tedescoの第二ソリューション: では少し複雑で、読み出します。
- ダニエル-Daranasソリューション: この作品でパクトアップコードで多くの不要な鋳造-デバッグ.Assert()記述です。
- hjb417のソリューション: このソリューションを上げすぎないことですすご理論に基底クラスです。ロジックには些細なこの例では(呼出しのコンストラクタが、現実世界に例するのではないです。
私の解決
このソリューションは克服すべての問題のように両方の使用により、ジェネリック医薬品および方法に隠されているのです。
public class Poo { }
public class RadioactivePoo : Poo { }
interface IAnimal
{
Poo Excrement { get; }
}
public class BaseAnimal<PooType> : IAnimal
where PooType : Poo, new()
{
Poo IAnimal.Excrement { get { return (Poo)this.Excrement; } }
public PooType Excrement
{
get { return new PooType(); }
}
}
public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }
本ソリューションだと思うのでオーバーライドなティッシュエンジニアリングをやり。ここでは一部の使用例:
Cat bruce = new Cat();
IAnimal bruceAsAnimal = bruce as IAnimal;
Console.WriteLine(bruce.Excrement.ToString());
Console.WriteLine(bruceAsAnimal.Excrement.ToString());
この出力は、このようになります:"RadioactivePoo"回はこの多型は壊れる。
さらに読む
- 明示的なインタフェース実装
- 新しい修飾子.使用していませんので簡単に解決できる必要があるので複雑な溶液とする。例えばしたい場合は、インタフェースを作成すためのBaseAnimalをする必要がありご利用いdeclerationの"PooType排泄物".
- ウェ改質剤(共分散).再び使用していませんので次回のプレゼンテーションもしたい場合は、次のように実行を返し
MyType<Poo>
からIAnimal返しMyType<PooType>
からBaseAnimalきを利用する必要がありますので間のキャストする。
このオプションもあります(明示的なインターフェイスの実装)
public class Cat:Animal
{
Poo Animal.Excrement { get { return Excrement; } }
public RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}
あなたは猫を実装する基本クラスを使用する能力を失うが、プラス側に、あなたは猫と犬の間で多型を維持します。
しかし、私は追加の複雑さは、それだけの価値がある疑います。
なぜ「排泄物」を作成し、保護された仮想メソッドを定義し、「排泄物」非仮想を返すパブリックプロパティを保持しません。その後、派生クラスは、ベースクラスの戻り型をオーバーライドすることができます。
次の例では、私は「排泄物」非仮想を作るものの派生クラスが適切な「うんち」を提供できるようにするために、プロパティExcrementImplを提供しています。派生型は、基本クラスの実装を非表示にすることで、「排泄物」の戻り値の型をオーバーライドすることができます。
E.x:ます。
namepace ConsoleApplication8
{
public class Poo { }
public class RadioactivePoo : Poo { }
public interface Animal
{
Poo Excrement { get; }
}
public class AnimalBase
{
public Poo Excrement { get { return ExcrementImpl; } }
protected virtual Poo ExcrementImpl
{
get { return new Poo(); }
}
}
public class Dog : AnimalBase
{
// No override, just return normal poo like normal animal
}
public class Cat : AnimalBase
{
protected override Poo ExcrementImpl
{
get { return new RadioactivePoo(); }
}
public new RadioactivePoo Excrement { get { return (RadioactivePoo)ExcrementImpl; } }
}
}
イム間違ったなら、私を修正しますが、イマイチpollymorphismの全体のポイントを、それはうんちを継承した場合、契約は抽象クラスと同じになりRadioActivePooを返すことができるようにちょうどRadioActivePooを返す()
これを試してください:
namespace ClassLibrary1
{
public interface Animal
{
Poo Excrement { get; }
}
public class Poo
{
}
public class RadioactivePoo
{
}
public class AnimalBase<T>
{
public virtual T Excrement
{
get { return default(T); }
}
}
public class Dog : AnimalBase<Poo>
{
// No override, just return normal poo like normal animal
}
public class Cat : AnimalBase<RadioactivePoo>
{
public override RadioactivePoo Excrement
{
get { return new RadioactivePoo(); }
}
}
}
私は、ジェネリックまたは拡張メソッドではなく、メソッドの隠蔽に依存しない方法を見つけたと思います。あなたは、さらに猫を継承場合には、多型を破ることができる、しかし、これは特に注意してください。
私はこのポストはまだ8ヶ月後半にも関わらず、誰かを助けることを願っています。
public interface Animal
{
Poo Excrement { get; }
}
public class Poo
{
}
public class RadioActivePoo : Poo
{
}
public class AnimalBase : Animal
{
public virtual Poo Excrement { get { return new Poo(); } }
}
public class Dog : AnimalBase
{
// No override, just return normal poo like normal animal
}
public class CatBase : AnimalBase
{
public override Poo Excrement { get { return new RadioActivePoo(); } }
}
public class Cat : CatBase
{
public new RadioActivePoo Excrement { get { return (RadioActivePoo) base.Excrement; } }
}
これは役立つかもしれない。
FYI。これはScalaで非常に簡単に実装されています。
trait Path
trait Resource
{
def copyTo(p: Path): Resource
}
class File extends Resource
{
override def copyTo(p: Path): File = new File
override def toString = "File"
}
class Directory extends Resource
{
override def copyTo(p: Path): Directory = new Directory
override def toString = "Directory"
}
val test: Resource = new Directory()
test.copyTo(null)
ここであなたが一緒にプレイすることができます実際の例です: http://www.scalakata.com/50d0d6e7e4b0a825d655e832
私はあなたの答えは、共分散と呼ばれていると信じています。
class Program
{
public class Poo
{
public virtual string Name { get{ return "Poo"; } }
}
public class RadioactivePoo : Poo
{
public override string Name { get { return "RadioactivePoo"; } }
public string DecayPeriod { get { return "Long time"; } }
}
public interface IAnimal<out T> where T : Poo
{
T Excrement { get; }
}
public class Animal<T>:IAnimal<T> where T : Poo
{
public T Excrement { get { return _excrement ?? (_excrement = (T) Activator.CreateInstance(typeof (T), new object[] {})); } }
private T _excrement;
}
public class Dog : Animal<Poo>{}
public class Cat : Animal<RadioactivePoo>{}
static void Main(string[] args)
{
var dog = new Dog();
var cat = new Cat();
IAnimal<Poo> animal1 = dog;
IAnimal<Poo> animal2 = cat;
Poo dogPoo = dog.Excrement;
//RadioactivePoo dogPoo2 = dog.Excrement; // Error, dog poo is not RadioactivePoo.
Poo catPoo = cat.Excrement;
RadioactivePoo catPoo2 = cat.Excrement;
Poo animal1Poo = animal1.Excrement;
Poo animal2Poo = animal2.Excrement;
//RadioactivePoo animal2RadioactivePoo = animal2.Excrement; // Error, IAnimal<Poo> reference do not know better.
Console.WriteLine("Dog poo name: {0}",dogPoo.Name);
Console.WriteLine("Cat poo name: {0}, decay period: {1}" ,catPoo.Name, catPoo2.DecayPeriod);
Console.WriteLine("Press any key");
var key = Console.ReadKey();
}
}
あなただけのリターン・インタフェースを使用することができます。あなたの場合は、IPoo。
あなたはコメントの基本クラスを使用しているため、これは、あなたのケースでは、ジェネリック型を使用することが好ましいです。
さて、おかげで、dynamic
を、(たとえ静的メソッドの)継承された戻り型から変化具象型を返すことが実際に可能です
public abstract class DynamicBaseClass
{
public static dynamic Get (int id) { throw new NotImplementedException(); }
}
public abstract class BaseClass : DynamicBaseClass
{
public static new BaseClass Get (int id) { return new BaseClass(id); }
}
public abstract class DefinitiveClass : BaseClass
{
public static new DefinitiveClass Get (int id) { return new DefinitiveClass(id);
}
public class Test
{
public static void Main()
{
var testBase = BaseClass.Get(5);
// No cast required, IntelliSense will even tell you
// that var is of type DefinitiveClass
var testDefinitive = DefinitiveClass.Get(10);
}
}
私は私の会社のために書いたAPIラッパーでこれを実装しました。あなたがAPIを開発することを計画している場合、これは、いくつかのユースケースでの使いやすさとのdevの体験を改善する可能性があります。それにも関わらず、<=>の使用は、パフォーマンスへの影響を持っているので、それを回避しよう。