Class A { }
Class B : A { }
B ItemB = new B();
A ItemA = (A)B;
Console.WriteLine(ItemA.GetType().FullName);
是否有可能做這樣的事情上面,並有編譯器打印出A型,而不是B型基本上是有可能永久性地投對象,因此「失去」的所有派生數據?永久投派生類基礎
Class A { }
Class B : A { }
B ItemB = new B();
A ItemA = (A)B;
Console.WriteLine(ItemA.GetType().FullName);
是否有可能做這樣的事情上面,並有編譯器打印出A型,而不是B型基本上是有可能永久性地投對象,因此「失去」的所有派生數據?永久投派生類基礎
什麼你問的原因有兩個是不可能的:
ItemA.GetType()
不返回變量ItemA
的編譯時類型 - 它返回的對象的運行時類型簡稱通過ItemA
。(A)B
導致表示更改轉換(即新的A
對象)。你只是想得到一個正常的,安全的參考轉換。那邊,你要求的是很奇怪的;人們會認爲你很難違反Liskov的替代原則。這裏幾乎肯定有一個嚴重的設計缺陷,您應該解決。
如果你還想這樣做,您可以編寫一種方法,手動構建B
中的A
,方法是創建A
,然後複製數據。這可能以B
上的ToA()
實例方法存在。
爲「?如何從現有一個構建一個」如果你將這個問題,這讓很多更有意義:創建A
一個拷貝構造函數,其聲明如下public A(A a){...}
,這是不可知以子類特定的細節。這給你一個通用的方法來創建A
現有的A
或它的一個子類實例。
不,您不能強制子類型的實例報告它的類型名稱是基類型。
請注意,當您使用指向B類實例的ItemA變量時,只能使用ItemA變量訪問A類中定義的字段和方法。在很少的地方,ItemA指向除類A以外的其他實例的事實實際上可以被觀察到 - 在子類中重寫的虛方法是一種情況,而對運行時類型本身的操作(如GetType())則是如此。
如果你問這個問題是因爲當你想要類A的一個實例時,它發送一個類B的實例時,某段代碼失敗了,這聽起來像你應該仔細看看那個代碼看看它做錯了什麼。如果它正在測試GetType.LastName,那麼它已經崩潰了,並且已經失去了靈感。如果它正在測試x IS A
,那麼傳遞B的實例將通過,一切都應該罰款。
爲了娛樂,如果你想失去所有所得到的數據,你可以這樣做:
class Program
{
[DataContract(Name = "A", Namespace = "http://www.ademo.com")]
public class A { }
[DataContract(Name = "A", Namespace = "http://www.ademo.com")]
public class B : A {
[DataMember()]
public string FirstName;
}
static void Main(string[] args)
{
B itemB = new B();
itemB.FirstName = "Fred";
A itemA = (A)itemB;
Console.WriteLine(itemA.GetType().FullName);
A wipedA = WipeAllTracesOfB(itemB);
Console.WriteLine(wipedA.GetType().FullName);
}
public static A WipeAllTracesOfB(A a)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(A));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, a);
ms.Position = 0;
A wiped = (A)serializer.ReadObject(ms);
return wiped;
}
}
}
如果您使用調試器,你會看到名字仍保存在該領域名字時,它是投到一個A,當你從WipeAllTracesOfB得到一個A時,沒有名字或任何B的蹤跡。
鑄造不會改變對象的類型。所有的轉換方式都是告訴編譯器什麼類型來處理對象(假設對象實際上是那種類型)。
A ItemA = (A)ItemB;
是說拿ItemB
,把它當作好像它是A
類型,並將其命名爲ItemA
當你調用ItemA.GetType()
你問真正的類型,不只是它被視爲類型,和真正的類型是B
(我改變了你的代碼示例什麼,我認爲你的意思,既然你不會編譯什麼)
(這可能是顯而易見的,但是......)
如果你仍然想做到這一點;您可以編寫一種方法,通過創建A然後複製數據來手動從B構建A。這可能是一個的ToA()實例方法存在於B.
或者使用Automapper將數據複製回:
Mapper.CreateMap<ChildClass, BaseClass>();
// ...later...
var wipedInstance = Mapper.Map<BaseClass>(instanceOfChildClass);
然後wipedInstance.GetType()
將typeof(BaseClass)
我最近跑將這個舊項目遷移到實體框架中。如前所述,如果您從實體獲得派生類型,則無法存儲它,而只能使用基本類型。 該解決方案是一種帶反射的擴展方法。
public static T ForceType<T>(this object o)
{
T res;
res = Activator.CreateInstance<T>();
Type x = o.GetType();
Type y = res.GetType();
foreach (var destinationProp in y.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
var sourceProp = x.GetProperty(destinationProp.Name);
if (sourceProp != null)
{
destinationProp.SetValue(res, sourceProp.GetValue(o));
}
}
return res;
}
它不是太整齊,所以如果你真的沒有其他選擇,就用這個。
在答案中加入爲什麼你不能這樣做,你真的不應該這樣做。當你想知道一個對象是否是基類的一種類型時,你不必檢查運行時類型是否相等,但是你可以使用`is`或`IsAssignableFrom`等特性。 – 2011-02-18 22:52:32
ItemA.GetType()。FullName輸出是什麼? `Namespace.B`? – 2011-02-18 22:55:08
是的,那時ItemA是B.我真正想要解決的是一個WCF需要確切類型的問題。我知道我可以使用KnownTypes,但如果可能的話,我寧願不使用KnownTypes。 – Telavian 2011-02-18 22:59:34