class DelegateTest<T> where T: // ....
{
public DelegateTest(DoSomethingDelegate<T> action = null)
{
if (action != null)
_doSomething = action;
else if (typeof(T) == typeof(int))
//_doSomething = DoSomethingInt; // fails
//_doSomething = (DoSomethingDelegate<T>)DoSomethingInt; // fails
//_doSomething = (DoSomethingDelegate<T>)((Delegate)DoSomethingInt); // fails
_doSomething = (val) => DoSomethingInt((int)((object)val)); // too ugly
else // ...
}
public void DoSomethingVeryComplex(T val)
{
// ....
_doSomething(val);
// ....
}
DoSomethingDelegate<T> _doSomething;
static void DoSomethingInt(int val)
{
}
}
delegate void DoSomethingDelegate<T>(T val);
因此,委托和方法通過簽名兼容,但是由于一些模糊的原因,這個分配不起作用,我完全不知道如何使它起作用。除了創建 shim 函式之外還有什么更好的想法嗎?
這個問題不是關于如何以其他方式重寫此代碼。這只是關于如何使這項任務發揮作用,如果那是不可能的 - 為什么。
uj5u.com熱心網友回復:
如果您使用Action<T>而不是自定義委托,則可以直接轉換和分配委托。
class DelegateTest<T>
{
public DelegateTest()
{
if (typeof(T) == typeof(int))
{
_doSomething = (Action<T>)(object)DoSomethingInt;
}
}
Action<T> _doSomething;
public void InvokeDoSomething(T x) => _doSomething(x);
static void DoSomethingInt(int val)
{
Console.WriteLine("Hello world! The argument was {0}", val);
}
}
快速測驗:
public class Program
{
public static async Task Main()
{
var o = new DelegateTest<int>();
o.InvokeDoSomething(1);
}
}
輸出:
Hello world! The argument was 1
小提琴
uj5u.com熱心網友回復:
既然你知道T,你可以強制this轉換為特定的泛型型別 ( DelegateTest<int>)。一旦你有了那個參考,你就可以使用它來對它的方法、屬性和欄位,甚至是私有的進行型別安全和特定型別的訪問。
class DelegateTest<T>
{
public DelegateTest()
{
if (typeof(T) == typeof(int))
{
var self = this as DelegateTest<int>; //Magic!!
self._doSomething = DoSomethingInt;
}
}
DoSomethingDelegate<T> _doSomething;
public void InvokeDoSomething(T x) => _doSomething(x);
static void DoSomethingInt(int val)
{
Console.WriteLine("Hello. The argument was {0}", val);
}
}
delegate void DoSomethingDelegate<T>(T val);
快速測驗:
public class Program
{
public static async Task Main()
{
var o = new DelegateTest<int>();
o.InvokeDoSomething(1);
}
}
輸出:
Hello. The argument was 1
鏈接到 DotNetFiddle
uj5u.com熱心網友回復:
類似于 John Wu 的第一個解決方案,但也適用于DoSomethingDelegate<T>:
static void Main()
{
new DelegateTest<int>().InvokeDoSomething(1);
new DelegateTest<string>().InvokeDoSomething("Hello");
}
delegate void DoSomethingDelegate<T>(T val);
class DelegateTest<T>
{
public DelegateTest()
{
if (typeof(T) == typeof(int))
_doSomething = new DoSomethingDelegate<T>((Action<T>)(object)DoSomethingInt);
else if (typeof(T) == typeof(string))
_doSomething = new DoSomethingDelegate<T>((Action<T>)(object)DoSomethingString);
else throw new NotSupportedException();
}
DoSomethingDelegate<T> _doSomething;
public void InvokeDoSomething(T x) => _doSomething(x);
void DoSomethingInt(int val) => Console.WriteLine($"DoSomethingInt({val})");
void DoSomethingString(string val) => Console.WriteLine($"DoSomethingString({val})");
}
輸出:
DoSomethingInt(1)
DoSomethingString(Hello)
在 Fiddle 上試試。
備選方案 1:正如 Enigmativity 在評論中提到的,也可以像這樣實作DoSomethingInt轉換:DoSomethingDelegate<T>
public DelegateTest()
{
if (typeof(T) == typeof(int))
_doSomething = (DoSomethingDelegate<T>)(Delegate)(DoSomethingDelegate<int>)DoSomethingInt;
else if (typeof(T) == typeof(string))
_doSomething = (DoSomethingDelegate<T>)(Delegate)(DoSomethingDelegate<string>)DoSomethingString;
else throw new NotSupportedException();
}
在 Fiddle 上試試。
與我最初的建議相比,它還使委托的呼叫速度提高了約 20%,原因由 Matthew Watson解釋。我最初的建議涉及兩個方法呼叫而不是一個。
備選方案 2: John Wu 的第二個解決方案的變體,使用switch陳述句而不是if as:
public DelegateTest()
{
switch (this)
{
case DelegateTest<int> self: self._doSomething = DoSomethingInt; break;
case DelegateTest<string> self: self._doSomething = DoSomethingString; break;
default: throw new NotSupportedException();
}
}
在 Fiddle 上試試。
這是型別安全的。您不能意外地將錯誤的方法分配給錯誤的型別。呼叫委托的速度與之前的備選方案 1 一樣快。
uj5u.com熱心網友回復:
首先,分配的問題是您處于DelegateTest<T>whereT可以是任何型別的范圍內,并且您要求編譯器允許將某些型別DoSomethingDelegate<int>分配給DoSomethingDelegate<T>. T如果在運行時那很好int,但編譯器不知道。盡管對型別進行了運行時檢查,但這是一個非法的強制轉換。
你能做的最好的事情就是讓你的代碼對編碼錯誤更有彈性。這是 Theo 答案的變體,它使代碼的型別更加強。這可能是您無需反思即可獲得的最佳效果。
static void Main()
{
new DelegateTest<int>().InvokeDoSomething(1);
new DelegateTest<string>().InvokeDoSomething("Hello");
}
delegate void DoSomethingDelegate<T>(T val);
class DelegateTest<T>
{
private Dictionary<Type, Delegate> _delegates = new Dictionary<Type, Delegate>();
private void Register<K>(DoSomethingDelegate<K> @delegate)
{
_delegates[typeof(K)] = @delegate;
}
public DelegateTest()
{
this.Register<int>(DoSomethingInt);
this.Register<string>(DoSomethingString);
if (_delegates.ContainsKey(typeof(T)))
{
_doSomething = (DoSomethingDelegate<T>)_delegates[typeof(T)];
}
else throw new NotSupportedException();
}
DoSomethingDelegate<T> _doSomething;
public void InvokeDoSomething(T x) => _doSomething(x);
void DoSomethingInt(int val) => Console.WriteLine($"DoSomethingInt({val})");
void DoSomethingString(string val) => Console.WriteLine($"DoSomethingString({val})");
}
輸出:
DoSomethingInt(1)
DoSomethingString(Hello)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/458739.html
上一篇:遍歷C#MVC中的串列并訪問屬性
