簡體   English   中英

使用泛型將類和方法名稱動態傳遞給方法

[英]Dynamically pass class and method names to a method using generics

我想動態地將類名和方法名傳遞給方法並保持動態,我理解我應該使用泛型和可能的約束。

例如,我有一個班級

MemberRequestDTO    (contains several properties)

我也是一個叫做的方法

RecordsToRetrieve

使用一些反射我想要動態獲取屬性的值,我想出了如何做到這一點,但后來我意識到這是太硬的代碼和緊密耦合,我想時間重構和創建一個方法與使用帶有約束的泛型的簽名。 在理解使用和約束等方面遇到麻煩。

所以我想傳入一個類名,並能夠在方法中使用它,反射我打算使用它,如:

Type type = typeof(classname);

我開始閱讀和研究,我開始玩這樣的代碼:

public void GetTypeValues<T>() where T : class , new()
  1. 如何傳遞MemberRequestDTO的類名?
  2. Generic對我來說是什么新東西?
  3. 如何將類名傳遞給parens()?
  4. 如果我使用它也會傳遞到parens?
  5. 我怎樣才能通過課程和方法?
  6. 閱讀上面的“其中T有約束(強制執行)”類型為“class AND new()”?

對此有點失落和困惑,請原諒我。

編輯:

基於答案和一些研究,我對此有了更多的理解:

讓我們忘記我試圖傳遞一種方法,說我只想傳遞一堂課

假設具有屬性的類看起來像這樣

 public class MemberRequestDTO
 {

    public DateTime DateRequested { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
  }

然后我會新建這個

var memberRequestDTO = new MemberRequestDTO();

然后我想把它傳遞給一個通用的方法

如何將對象的實例傳遞給泛型方法? 那簽名怎么樣,示例public void GetTypeValues()其中T:class,new()
我想要有類和new()的約束嗎?

對於上面的,是T類的實例? 因此,目的是我可以

GetTypeValues(memberRequestDTO)      

(這是我的實際問題, 進入我實例化的任何類,並讓方法“處理”處理該類,循環遍歷屬性並動態獲取屬性的名稱值,是的,它可能不會保持為void方法)

應該在memberRequestDTO中傳遞引號還是不引用? 我希望能夠將任何類的實例傳遞給成員,然后再操作它。 ()應該是嗎? parens()應該為空還是包含類對象的泛型參數?

如何傳遞MemberRequestDTO的類名?

你已經有一個。 在通用方法中,“Type parameter”在這種情況下, T將是您感興趣的類型的名稱。

public void GetTypeValues<T>() where T : class , new()
{
    string typeName = typeof(T).Name;
}

Generic對我來說是什么新東西?

這是一個禁令,它將阻止您在沒有公共無參數構造函數的情況下傳遞任何類型。 換句話說,它將允許您作為“類型參數”傳入的新的類型

public void GetTypeValues<T>() where T : class , new()
{
    T instance = new T();//This is not possible without new constraint
}

如何將類名傳遞給parens()?

如果我使用它也會傳遞到parens?

不確定是什么parens()需要更多信息來回答這個問題。

我怎樣才能通過課程和方法?

如果我理解正確“類型參數” T是您使用的運行時類型。 所以你在那里得到一個Type 我不確定你的課程是什么意思? 類不能傳遞只能傳遞實例。

對於方法,有很多種方法。 您可以傳遞MethodInfo或方法名稱或A委托,或MethodCallExpression等。

閱讀上面的“其中T有約束(強制執行)”類型為“class AND new()”?

是。 類約束阻止您傳遞值類型,new()約束允許您新建事物。

在這里這里閱讀更多關於泛型的信息

這是你的答案:

  1. GetTypeValues<MemberRequestDTO>()
  2. new()Type Parameter - T的約束。 它表示類型參數T必須具有公共無參數構造函數。 在您的情況下, MemberRequestDTO類必須是一個公共無參數構造函數,如下所示:

     public class MemberRequestDTO { public MemberRequestDTO() { ... } } 
  3. 由於類名是reference type ,您可以將其作為type傳遞給parens,如: SomeMethod(typeof(MemberRequestDTO)); 其中方法的簽名為void SomeMethod(Type type) { }

  4. 如果您將類作為type parameter傳遞,如在點(1)中,它不會傳遞到parens()

  5. class約束意味着“類型參數必須是引用類型;這也適用於任何類,接口,委托或數組類型。” new()約束意味着“類型參數必須具有公共無參數構造函數。當與其他約束一起使用時,必須最后指定new()約束。”


編輯:

如果我抓住你的觀點,那么泛型方法定義將是這樣的:

public void GetTypeValues<T>(T typeObject) where T : class
{
    // typeObject specific operations
}

它動態地使用typeObject ,讓“執行時編譯器”執行類型推斷來計算出T 請參閱此處的參考。 而且,imho,你不需要對Tnew ()約束。

之后,您可以將任何類的實例傳遞給此方法,如下所示:

var memberRequestDTO = new MemberRequestDTO();
GetTypeValues((dynamic) memberRequestDTO);

編輯2:

用法:使用Reflection動態獲取類型值

此方法將包裝的屬性值返回到IEnumerable<KeyValuePair<string, object>>

public static IEnumerable<KeyValuePair<string, object>> GetTypeValues<T>(T typeObject) where T : class
{
    // typeObject specific operations
    IEnumerable<KeyValuePair<string, object>> typeValues = 
        typeObject
        .GetType()
        .GetProperties()
        .Select(property => new KeyValuePair<string, object>(property.Name, property.GetValue(typeObject)));
    return typeValues;
}

我對你想做什么感到有點困惑,但我會試一試。 我可以看到兩種可能的解釋,它們在調用者的開始和你想要實現的目標上有所不同。

解讀一:主叫方開出知道類的名稱 ,它希望以后調用,使用它在手的對象方法的名稱 這可以通過以下方式實現:

public Func<object, object> RecordMethod(string typeName, string methodName)
{
    var type = Type.GetType(typeName);
    var method = type.GetMethod(methodName);
    return (object o) => method.Invoke(o, new object[0]);
}

var method = RecordMethod("MemberRequestDTO", "RecordsToRetrieve");

// later that day ...
MemberRequestDTO someObj = ...;
var result = method.Invoke(someObj);

如果您需要動態處理類型名稱和方法名稱(例如,來自用戶輸入),這很好。 請注意,此方法需要始終使用object ,並且只能使用不帶參數的方法。 還要注意,通過這種方式,類型不能保證具有無參數構造函數,因此調用者必須自己提供該對象。

解釋#2:調用者使用稍后可以構造的對象開始知道它想要稍后調用的實際類和實際方法。 這可以通過以下方式實現:

public Func<TOutput> CaptureMethod<TInput, TOutput>(Func<TInput, TOutput> method) 
where TInput : new()
{
    return () =>
    {
        var source = new TInput();
        return method(source);
    };
}

var capturedMethod = (MemberRequestDTO dto) => dto.RecordsToRetrieve();

// later that day ...
var result = capturedMethod();

這將捕獲一個已知方法並返回一個函數,該函數在被調用時將實例化您的類並在其上調用該方法。 這是一種更靜態的方法(調用者比前面的例子更了解),並且能夠強制執行約束,使用的類型必須具有無參數構造函數。

我不知道我是否回答了你的問題,但這至少應該給你一些想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM