這與這個問題從泛型方法中呼叫多載的泛型方法類似,但并不一樣:在這種情況下,該方法回傳void,而我需要回傳泛型T,所以建議的解決方案并不可行。
我正在實作一個類似元組的類,它有通用引數和這些引數的訪問器:
我正在實作一個類似元組的類,它有通用引數和這些引數的訪問器。
public class MyClass< T1, T2>
{
private readonly T1 _item1。
private readonly T2 _item2;
public MyClass(T1 item1, T2 item2)
{
_item1 = item1。
_item2 = item2。
}
public T1 GetItem(T1 _) => _item1。
public T2 GetItem(T2 _) => _item2。
private T GetItem<T> (T x)
{
throw new ArgumentException();
//return x;
}
public T Get<T>()
{
return GetItem(default(T))。
}
我想這樣使用這個類:
我想這樣使用這個類。
var obj = new MyClass< int, string>(1, "hello") 。
var a = obj.Get<int>()。
var b = obj.Get<string>()。
但是如果我嘗試這樣做,通用的T GetItem<T>(T x)總是被呼叫(拋出例外),而不是非通用的實作。
如果我嘗試直接訪問GetItem方法,它可以按預期的那樣作業:
var obj = new MyClass< int, string>(1, "hello") 。
var q = obj.GetItem(default(int);
var w = obj.GetItem(default(string)) 。
q和w包含1和hello,符合預期。
是否有辦法讓我按照我的意愿使用這個類(使用obj.Get<T>)?我想避免使用Item1 Item2 Item3 getters。
uj5u.com熱心網友回復:
但是如果我嘗試這樣做,通用的
T GetItem<T>(T x)總是被呼叫(例外被拋出),而不是非通用的實作。
這是因為多載決議發生在編譯時,而在編譯時,T的具體型別是未知的。
是否有辦法讓我按照我的意愿使用這個類(使用
obj.Get<T>)?
使用普通的動態型別檢查,當然可以:
public class MyClass< T1, T2>
{
private readonly T1 _item1。
private readonly T2 _item2;
public MyClass(T1 item1, T2 item2)
{
_item1 = item1。
_item2 = item2。
}
public T Get<T>()
{
if (typeof(T) == typeof(T1)
{
return (T)(object)_item1;
}
if (typeof(T) == typeof(T2))
{
return(T)(object)_item2。
}
throw new InvalidOperationException();
}
這個解決方案的好處是,邊緣情況(T1 == T2,或者T既不匹配T1也不匹配T2)的行為被正確定義,并且很容易看到。
另外,你可以使用你鏈接的問題中使用的
dynamic"黑客",你只需要將結果投到T。return (T)GetItem((dynamic)default(T));, 這里有一個working fiddle。
但是這實在是太難看了,請不要這樣做。比較一下這個謎語和上面的版本,試著誠實地判斷哪一個更容易閱讀,更容易理解,因此更容易維護。
uj5u.com熱心網友回復:
測驗
var instance = new MyClass< string, int>("hello", 1) 。
Console.WriteLine(instance.GetItem("hi") )。
Console.WriteLine(instance.GetItem(2) )。
//回傳 "hello"。
Console.WriteLine(instance.Get<string> ())。
//回傳 "1"。
Console.WriteLine(instance.Get<int>()) 。
//throws with details
Console.WriteLine(instance.Get<object>()) 。
實施
public T Get< T>()
{
var parentType = typeof(MyClass<T1, T2>)。
var method = parentType.GetMethod(nameof(GetItem), new[] { typeof(T) }) 。
if (method == null)
throw new NotImplementedException(
$"No implementation for {nameof(GetItem)} with parameter type {typeof(T) .FullName}"/span>)。)
var result = (T)method.Invoke(this, new object[] { default(T) }) ;
return result。
}
這個版本使用反射。如果你需要更多的性能,你應該選擇編譯的運算式,但這更難維護
。uj5u.com熱心網友回復:
如果你對兩個專案有相同的資料型別呢?
var obj = new MyClass< int, int>(1, 2) 。
這里GetItem應該回傳什么?很明顯,這個問題沒有有效的答案。
無論如何,提供一個引數只是為了區分呼叫哪個方法是非常奇怪的。實際上你的GetItem<T>方法根本就不應該是通用的。只需使用兩個不同的方法:
T1 GetItem1(/span>)/span> => _item1;
T2 GetItem2() => _item2;
或者使用自動屬性來擺脫后置欄位:
或者使用自動屬性來擺脫后置欄位。
public class MyClass < T1, T2>
{
public T1 Item1 { get; }
public T2 Item2 { get; }
public MyClass(T1 item1, T2 item2)
{
item1 = item1;
Item2 = item2;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/330175.html
標籤:
上一篇:如何將兩個類似的方法轉換為一個?
下一篇:具有方差的引數化資料類
