で与することができるベースのclassオブジェクトが派生クラスへの参照明示的網?

StackOverflow https://stackoverflow.com/questions/729527

質問

で与することができるベースのclassオブジェクトが派生クラスへの参照明示的網クライアントまで、フルのC#?.

していたのであるというように実行時エラーとなります。

役に立ちましたか?

解決

はありません。派生クラスへの参照は、実際には、派生クラス(またはnull)のインスタンスを参照しなければなりません。そうしないとどのようにあなたはそれが動作するように期待する?

object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?

あなたは派生型に基本型のインスタンスに変換することができるようにしたい場合は、私はあなたが適切な派生型のインスタンスを作成する方法を記述し示唆しています。または、もう一度継承ツリーを見て、あなたが最初の場所でこれを実行する必要がないように再設計してみます。

他のヒント

派生クラス参照に代入すると、派生クラスので、真実ではないとする、「基本クラスが派生クラスの完全に可能代わるもので、それは派生クラスが行うことができるすべてを行うことができます」というようなことであろうから、

いいえ、それは不可能です一般的には(少なくとも、それは継承の背後にある考え方だ)その基底クラスよりも多くの機能を提供します。

あなたは値をコピー、パラメータとして、基本クラスのオブジェクトを取る派生クラスでコンストラクタを書くことができます。

このような何かます:

public class Base {
    public int Data;

    public void DoStuff() {
        // Do stuff with data
    }
}

public class Derived : Base {
    public int OtherData;

    public Derived(Base b) {
        this.Data = b.Data;
        OtherData = 0; // default value
    }

    public void DoOtherStuff() {
        // Do some other stuff
    }
}

その場合、あなたはベースオブジェクトをコピーして、派生メンバーのデフォルト値を使って、完全に機能する派生クラスのオブジェクトを取得します。あなたはまた、問題を回避することができるこの方法は、ジョンスキートによって指摘されます:

Base b = new Base();
Dervided d = new Derived();

b.DoStuff();    // OK
d.DoStuff();    // Also OK
b.DoOtherStuff();    // Won't work!
d.DoOtherStuff();    // OK

d = new Derived(b);  // Copy construct a Derived with values of b
d.DoOtherStuff();    // Now works!

私はこの問題を持っていたタイプのパラメータを取り、その型に現在のオブジェクトを変換する方法を追加することによってそれを解決します。

public TA As<TA>() where TA : Base
{
    var type = typeof (TA);
    var instance = Activator.CreateInstance(type);

     PropertyInfo[] properties = type.GetProperties();
     foreach (var property in properties)
     {
         property.SetValue(instance, property.GetValue(this, null), null);
     }

     return (TA)instance;
}

それはあなたがこのようなあなたのコードでそれを使用することができることを意味します:

var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1

として、他の多くはありません、答えています。

私は派生型として基本型を使用する必要がある場合、

私はそれらの不運な機会に、次のコードを使用します。はい、それはリスコフの置換原則(LSP)の違反であるとイエスの時間のほとんどは、我々は、継承以上の組成を好みます。オリジナルの答えはこれが基づいているマルクスKnappenヨハンソンの小道具ます。

基底クラスでこのコード

    public T As<T>()
    {
        var type = typeof(T);
        var instance = Activator.CreateInstance(type);

        if (type.BaseType != null)
        {
            var properties = type.BaseType.GetProperties();
            foreach (var property in properties)
                if (property.CanWrite)
                    property.SetValue(instance, property.GetValue(this, null), null);
        }

        return (T) instance;
    }

ができます:

    derivedObject = baseObect.As<derivedType>()
それはリフレクションを使用しているので、

、それは「高価」です。それに応じて使用します。

はありません、それはそれゆえ、あなたのランタイムエラーことはできません。

しかし、あなたは、基本クラス型の変数に派生クラスのインスタンスを割り当てることができます。

ここでは誰もが言ったように、

、それが直接ことはできません。

私は好むとかなりきれいである方法は、 AutoMapper のようなオブジェクトマッパーを使用することです。

これは、自動的に別のインスタンスから(必ずしも同じタイプ)をコピープロパティの作業を行います。

できるキャスト 変数 この入力の基盤としてのクラスのインターネットブラウザの派生クラスしかし、必要なこんなでランタイムチェックを見れば実際のオブジェクト関係の正しいタイプです。

一度作成さ タイプ オブジェクトの変更はできません(以外にない場合があったので、それを同じサイズ)。できるだ 変換 インスタンスを作り出 新しい インスタンスの型が記述する必要がありますの換算コードになります。

YBOの答え@上の拡大 - 基底クラスのあなたが持っているインスタンスは、実際に派生クラスのインスタンスではありませんので、それは不可能です。それだけで、基本クラスのメンバーを知っている、と派生クラスのについては何も知りません。

それはすでにこれらのメンバーを持っているため、派生クラスが実際に既に、基底クラスのインスタンスであるため、

あなたは、基本クラスのインスタンスに派生クラスのインスタンスをキャストすることができた理由です。逆に言うことはできません。

いいえ、それは不可能です。

ACBusベースクラスバスの派生クラスであるシナリオを考えます。 ACBusはACStateという名前のフィールドを操作TurnOnACとTurnOffACなどの機能を備えています。 TurnOnACはACStateをオンに設定し、TurnOffACはオフにACStateを設定します。あなたはバスにTurnOnACとTurnOffAC機能を使用しようとすると、それは意味をなさないます。

class Program
{
    static void Main(string[] args)
    {
        a a1 = new b();  
        a1.print();  
    }
}
class a
{
    public a()
    {
        Console.WriteLine("base class object initiated");
    }
    public void print()
    {
        Console.WriteLine("base");
    }
}
class b:a
{
    public b()
    {
        Console.WriteLine("child class object");
    }
    public void print1()
    {
        Console.WriteLine("derived");
    }
}

}

私たちは子クラスのオブジェクトを作成するときに、基本クラスのオブジェクトはとても基本クラス参照変数開始自動で子クラスのオブジェクトを指すことができます。

はなく、その逆の子クラス・オブジェクトが作成されないため、子クラス参照変数は、基本クラスオブジェクトを指すことができないからである。

また、その基本クラスの参照変数に気づく基本クラスのメンバのみ呼び出すことができます。

が実際にはよろしくお願いします。とされていることについて利用する場合もあるでしょうNewtonsoft JSONを直列化復元オブジェクトからのjson.(少なくとも可能)無欠の要素と移植すべての要素を取り入れるとともに、ほこりだ。

こうしてよかったです。小コードサンプルに従って説明を受けます。

  1. インスタンスを生成するのオブジェクトから、基本クラスの読み込みます。

  2. "を用いjsonconvert"クラスのNewtonsoft json、serializeそのオブジェクトをjson文字列になります。

  3. 今作のサブクラスオブジェクトによるdeserializingのjson文字列で作成したステップ2に進みます。この作インスタンスのサブクラスのプロパティはすべて基底クラスです。

この作品のような魅力!いです。すがこちら。一部の人たがこのような示唆を変更するOPのスキーマを収容することができるというのもなネイティブなクラスの継承(ます。して順調なものではなかった。

私の場合、設定のクラスを含むすべての設定のためのサービスです。特定のサービスオプションの方からの異なるDBテーブル、その国にとって良いとは限らない授業を受け継ぐの基底クラスです。すべて異なるのです。で取得時のデータをサービスですの最初の移植の価値観をインスタンスのベースオブジェクトです。一方このシェアードDBクエリ.直後に、どうしたらいいでしょうかをサブクラスオブジェクトを使用方法を概説する。私はその第二のクエリの読み込みのすべての動的価値のサブクラスのオブジェクトです。

最終出力を導出クラスのすべてのオプションセットです。これを繰り返しのための追加新しいサブクまでわずか数行のコードです。シンプルで利用して、非常にこれらのパッケージ(Newtonsoft)のマジックです。

この例のコードがvb.Netが簡単に変換できるc#.

' First, create the base settings object.
    Dim basePMSettngs As gtmaPayMethodSettings = gtmaPayments.getBasePayMethodSetting(payTypeId, account_id)
    Dim basePMSettingsJson As String = JsonConvert.SerializeObject(basePMSettngs, Formatting.Indented)

    ' Create a pmSettings object of this specific type of payment and inherit from the base class object
    Dim pmSettings As gtmaPayMethodAimACHSettings = JsonConvert.DeserializeObject(Of gtmaPayMethodAimACHSettings)(basePMSettingsJson)

はreleventではないかもしれないが、私はそのベース所与の派生オブジェクト上でコードを実行することができました。それは私が希望よりも間違いなく多くのハックですが、それは動作します:

public static T Cast<T>(object obj)
{
    return (T)obj;
}

...

//Invoke parent object's json function
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(baseObj.GetType());
object castedObject = castMethod.Invoke(null, new object[] { baseObj });
MethodInfo jsonMethod = baseObj.GetType ().GetMethod ("ToJSON");
return (string)jsonMethod.Invoke (castedObject,null);

あなたは拡張子を使用することができます:

public static void CopyOnlyEqualProperties<T>(this T objDest, object objSource) where T : class
    {
        foreach (PropertyInfo propInfo in typeof(T).GetProperties())
            if (objSource.GetType().GetProperties().Any(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()))
                propInfo.SetValue(objDest, objSource.GetType().GetProperties().First(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()).GetValue(objSource));
    }

コードでます:

public class BaseClass
{
  public string test{ get; set;}
}
public Derived : BaseClass
{
//Some properies
}

public void CopyProps()
{
   BaseClass baseCl =new BaseClass();
   baseCl.test="Hello";
   Derived drv=new Derived();
   drv.CopyOnlyEqualProperties(baseCl);
   //Should return Hello to the console now in derived class.
   Console.WriteLine(drv.test);

}

私は、これは古いです知っているが、私はかなりしばらくの間、これを正常に使用しました。

   private void PopulateDerivedFromBase<TB,TD>(TB baseclass,TD derivedclass)
    {
        //get our baseclass properties
        var bprops = baseclass.GetType().GetProperties();
        foreach (var bprop in bprops)
        {
            //get the corresponding property in the derived class
            var dprop = derivedclass.GetType().GetProperty(bprop.Name);
            //if the derived property exists and it's writable, set the value
            if (dprop != null && dprop.CanWrite)
                dprop.SetValue(derivedclass,bprop.GetValue(baseclass, null),null);
        }
    } 

(代わり型キャストの)JsonConvert有する溶液

今日JsonConvertを使用しての私は、同じ問題に直面し、私は問題にシンプルでの迅速な解決策を見つけます。

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);

別の解決策は、拡張メソッドを追加することですので、同様ます:

 public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true)
        {
            try
            {
                if (sourceObject != null)
                {
                    PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties();
                    List<string> sourcePropNames = sourceProps.Select(p => p.Name).ToList();
                    foreach (PropertyInfo pi in destinationObject.GetType().GetProperties())
                    {
                        if (sourcePropNames.Contains(pi.Name))
                        {
                            PropertyInfo sourceProp = sourceProps.First(srcProp => srcProp.Name == pi.Name);
                            if (sourceProp.PropertyType == pi.PropertyType)
                                if (overwriteAll || pi.GetValue(destinationObject, null) == null)
                                {
                                    pi.SetValue(destinationObject, sourceProp.GetValue(sourceObject, null), null);
                                }
                        }
                    }
                }
            }
            catch (ApplicationException ex)
            {
                throw;
            }
        }

次に、ベースクラスを受け入れる各派生クラスのコンストラクタを有します

  public class DerivedClass: BaseClass
    { 
        public DerivedClass(BaseClass baseModel)
        {
            this.CopyProperties(baseModel);
        }
    }
既に設定され(nullでない)かどう

また、必要に応じて宛先プロパティを上書きします。

  

?。C#で明示的な型キャストを持つ派生クラスの基準に基本クラスのオブジェクトを割り当てることが可能です

だけではなく、明示的でなく、暗黙的な変換が可能であります。

C#言語は、このような変換演算子を許可していませんが、あなたはまだ、純粋なC#を使用してそれらを書くことができ、彼らが働きます。暗黙的な変換演算子(Derived)およびオペレータ(Program)を使用してクラスを定義するクラスが別のアセンブリで定義されなければならないことに留意されたい(例えばDerivedクラスはlibrary.dllクラスを含むprogram.exeによって参照さProgramです)。

//In library.dll:
public class Base { }

public class Derived {
    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Implicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }

    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Explicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }
}

//In program.exe:
class Program {
    static void Main(string[] args) {
        Derived z = new Base(); //Visual Studio can show squiggles here, but it compiles just fine.
    }
}
あなたは、Visual Studioのプロジェクト参照を使用してライブラリを参照するときは、暗黙の型変換を使用する場合、

は、VSは波線を示したが、それはうまくコンパイルします。あなただけのlibrary.dllを参照する場合は、波線はありません。

させることができ用のクラスを提供します。.

public class BaseClass
{
    public int A { get; set; }
    public int B { get; set; }
    private T ConvertTo<T>() where T : BaseClass, new()
    {
         return new T
         {
             A = A,
             B = B
         }
    }

    public DerivedClass1 ConvertToDerivedClass1()
    {
         return ConvertTo<DerivedClass1>();
    }

    public DerivedClass2 ConvertToDerivedClass2()
    {
         return ConvertTo<DerivedClass2>();
    }
}

public class DerivedClass1 : BaseClass
{
    public int C { get; set; }
}

public class DerivedClass2 : BaseClass
{
    public int D { get; set; }
}

かの特典を利用します。

  1. なく複製のコード
  2. を使用しているのではない反射(遅い)
  3. すべての変換は一つの場所

組み合わせた一部の前の答え(これらの者たちにシンプルな静的クラスの二つの方法がいます。

そう、シンプルなカバーすべてのシナリオはあまりにすることにより、より良い,いいえ、ありません、ありができるのではないかと思ったより効率的でとてもいいかもしれませんのものからスライスパン、ありあふれる力強nugetパッケージオブジェクトmappersあるような激しい使用など、矢田矢田で当社の基本的ニーズもの:)

もちろんでいる地図の値からオブジェクトをanyオブジェクトに由来していますの公共性という名のと同じコースを無視しですので

使用量:

SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };

// creates new object of type "RealPerson" and assigns any matching property 
// values from the puppet object 
// (this method requires that "RealPerson" have a parameterless constructor )
RealPerson person = ObjectMapper.MapToNewObject<RealPerson>(puppet);

// OR

// create the person object on our own 
// (so RealPerson can have any constructor type that it wants)
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
RealPerson person = new RealPerson("tall") {Name = "Steve"};

// maps and overwrites any matching property values from 
// the puppet object to the person object so now our person's age will get set to 5 and
// the name "Steve" will get overwritten with "Elmo" in this example
ObjectMapper.MapToExistingObject(puppet, person);

静ユーティリティクラス:

public static class ObjectMapper
{
    // the target object is created on the fly and the target type 
    // must have a parameterless constructor (either compiler-generated or explicit) 
    public static Ttarget MapToNewObject<Ttarget>(object sourceobject) where Ttarget : new()
    {
        // create an instance of the target class
        Ttarget targetobject = (Ttarget)Activator.CreateInstance(typeof(Ttarget));

        // map the source properties to the target object
        MapToExistingObject(sourceobject, targetobject);

        return targetobject;
    }

    // the target object is created beforehand and passed in
    public static void MapToExistingObject(object sourceobject, object targetobject)
    {
        // get the list of properties available in source class
        var sourceproperties = sourceobject.GetType().GetProperties().ToList();

        // loop through source object properties
        sourceproperties.ForEach(sourceproperty => {

            var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);

            // check whether that property is present in target class and is writeable
            if (targetProp != null && targetProp.CanWrite)
            {
                // if present get the value and map it
                var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
                targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
            }
        });
    }
}

いかがます:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }

派生項目にすべての基本プロパティを追加するための最良の方法は、costructorに使用反映しています。メソッドまたはインスタンスを作成せずに、このコードを試してみてください。

    public Derived(Base item) :base()
    {

        Type type = item.GetType();

        System.Reflection.PropertyInfo[] properties = type.GetProperties();
        foreach (var property in properties)
        {
            try
            {
                property.SetValue(this, property.GetValue(item, null), null);
            }
            catch (Exception) { }
        }

    }

私はそれが不可能であることを同意しません。あなたはこのようにそれを行うことができます:

public class Auto 
{ 
    public string Make {get; set;}
    public string Model {get; set;}
}

public class Sedan : Auto
{ 
    public int NumberOfDoors {get; set;}
}

public static T ConvertAuto<T>(Sedan sedan) where T : class
{
    object auto = sedan;
    return (T)loc;
}

使用方法:

var sedan = new Sedan();
sedan.NumberOfDoors = 4;
var auto = ConvertAuto<Auto>(sedan);

いいえ、私は尋ねたこの質問を参照 - アップキャスト.NETのジェネリックを使用してをする

最善の方法は、クラスのデフォルトコンストラクタを作る構築し、その後Initialiseメソッドを呼び出すことです。

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