[英]How to return dynamic return types in methods? C#
我遇到了方法的返回類型的問題。
該方法返回一個linq對象,該對象目前返回類型tblAppointment。 此方法如下所示:
public tblAppointment GetAppointment(int id)
{
var singleAppointment = (from a in dc.tblAppointments
where a.appID == id
select a).SingleOrDefault();
return singleAppointment;
}
問題是tblAppointment是抽象的並且有許多繼承它的子類型。 當我嘗試返回類型為“appointmentTypeA”的對象並在其上調用.GetType()方法時,它為我提供了正確的子類型,但是當我嘗試訪問屬性時,它只允許我訪問父屬性。 如果我拿走對象並將它投射到子類型的新對象然后它工作,讓我訪問我需要的一切,但它似乎很亂。
var viewSingleAppointment = appointmentRepos.GetAppointment(appointmentId);
Debug.Write(viewSingleAppointment.GetType()); //returns type i want
if (viewSingleAppointment is tblSingleBirthAppointment)
{
tblSingleBirthAppointment myApp = (tblSingleBirthAppointment)viewSingleAppointment; //need to do this to access TypeA properties for some reason
}
編輯:我有這個工作,但我需要為每個約會使用一個select語句(大約20)並將它們轉換為適當的類型並檢索屬性,我不知道如何重構它,因為它將在幾個頁面上使用我們正在做。
好吧,如果你正在使用C#4,你可以使用動態類型...但是如果你想堅持靜態類型,我懷疑你能做的最好就是提供預期類型作為泛型類型參數,並獲得方法為你執行演員:
public T GetAppointment<T>(int id) where T : tblAppointment
{
var singleAppointment = (from a in dc.tblAppointments
where a.appID == id
select a).SingleOrDefault();
return (T) singleAppointment;
}
稱之為:
SpecificAppointment app = GetAppointment<SpecificAppointment>(10);
或使用隱式輸入:
var app = GetAppointment<SpecificAppointment>(10);
如果轉換失敗,它將在執行時拋出異常。
這假設調用者知道約會類型(盡管他們可以指定tblAppointment
如果他們不知道)。 在編譯時不知道適當的約會類型,很難看出靜態類型如何能為你帶來更多好處,真的......
你正在解決錯誤的問題。 如果您有一個超類A
,子類B
, C
等,它們都具有類似的功能,那么您需要執行以下操作:
使A
成為B
, C
等實現的接口。 與B
或C
實例一起使用的代碼通過A
提供的接口完成。 如果您可以定義一組適用於所有類型的通用操作,那么這就是您需要做的。
如果您無法定義一組通用操作,例如,您的代碼類似於:
A foo = GetA(); if(foo is B) { B bFoo = (B) foo; // Do something with foo as a B } else if(foo is C) { C cFoo = (C) foo; // Do something with foo as a C } ...
甚至這個(基本上是相同的,只是使用額外的信息來模擬系統已經為你提供的類型):
A foo = GetA(); MyEnum enumeratedValue = foo.GetEnumeratedValue(); switch(enumeratedValue) { case MyEnum.B: B bFoo = (B) foo; // Do something with foo as a B break; case MyEnum.C: C cFoo = (C) foo; // Do something with foo as a C break; }
然后你真正想要做的事情是:
A foo = GetA(); foo.DoSomething();
其中每個子類都將實現switch
語句的相應分支。 這在幾個方面實際上更好:
B
和C
實現分開的大型switch
/ case
塊,因此如果添加新的子類,您不會冒任何意外忘記添加相應case
風險。 如果將DoSomething()
方法保留在A
的子類之外,則會出現編譯時錯誤。 編輯 :回復您的評論:
如果您的DoSomething()
例程需要在Form
或其他GUI元素上運行,只需將該元素傳遞給方法即可。 例如:
public class B : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a B object!";
}
}
public class C : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a C object!";
}
}
// elsewhere, in a method of MyForm:
A foo = GetA();
foo.DoSomething(this);
或者,更好的想法可能是將B
和C
類轉換為自定義控件,因為它們似乎封裝了顯示邏輯。
您可以創建一個通用方法:
public T GetAppointment<T>(int id) where T : tblAppointment
{
var singleAppointment = dc.tblAppointments.SingleOrDefault(a => a.appID == id);
return (T)singleAppointment;
}
但是在調用它之前你需要知道對象的實際類型...
當您調用.GetType()
,您將獲得該對象的運行時類型。 C#編譯器不知道您的對象將具有哪種運行時類型。 它只知道你的對象將是一個派生自tblAppointment
的類型,因為你在方法聲明中這么說,所以返回值的靜態類型是tblAppointment
。 因此tblAppointment
是你可以訪問的全部,除非你使用強制轉換告訴編譯器«我知道在運行時這個引用將引用這種類型的對象,插入運行時檢查並給我一個這種靜態類型的引用» 。
靜態類型是在編譯時和運行時已知的類型之間的差異。 如果你來自像Smalltalk或Javascript這樣的動態類型語言,你將不得不對你的編程習慣和思考過程進行一些調整。 例如,如果您必須對依賴於其運行時類型的對象執行某些操作,則解決方案通常是使用虛函數 - 它們會調度對象的運行時類型。
更新:在您的特定情況下,使用虛擬功能,這正是它們的用途:
class tblAppointment
{
protected abstract void ProcessAppointment () ;
}
sealed class tblBirthAppointment
{
protected override void ProcessAppointment ()
{
// `this` is guaranteed to be tblBirthAppointment
// do whatever you need
}
}
...
然后用
// will dispatch on runtime type
appointmentsRepo.GetAppointment (id).ProcessAppointment () ;
您可以創建另一種方法來封裝轉換:
public tblSingleBirthAppointment GetBirthAppointment(int id)
{
var singleAppointment = GetAppointment(id);
if (singleAppointment != null)
{
return (tblSingleBirthAppointment)singleAppointment;
}
return null;
}
如果您嘗試將其用於實際上不是BirthAppointment的ID,那么該方法會破壞,因此您可以考慮進行檢查。
var viewSingleBirthAppointment = appointmentRepos.GetBirthAppointment(appointmentId);
如果要返回對父類型的子類型的引用,則引用將屬於該類型,並且編譯器將不允許您訪問任何子類型的成員,直到轉換為該類型。 這是行動中的多態性:)
好消息是,在轉換引用類型時,您不是在創建新對象 - 您只需更改指向您已有對象的引用類型,從而為您提供對其成員的訪問權限。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.