当我们将泛型参数作为“Type”类型的变量时,如何在运行时将变量强制转换为泛型:
这是我试图解决的一个小试验。这是一个人为的例子,但说明了我的问题。
using System;
using System.Linq;
using NUnit.Framework;
namespace MyApp.Tests
{
public interface IMagicConverter<T>
{
T ConvertIt(int input);
}
/// <summary>
/// Convert and int to a somewhat related string
/// </summary>
public class MyStringConverter : IMagicConverter<string>
{
public string ConvertIt(int input)
{
switch (input)
{
case 1:
return "Number one";
case 2:
return "Number two";
default:
return "Another number";
}
}
}
/// <summary>
/// Convert a int to a somewhat related date
/// </summary>
public class MyDateTimeConverter : IMagicConverter<DateTime>
{
public DateTime ConvertIt(int input)
{
return DateTime.Today.AddDays(input);
}
}
public class TestClass
{
// at this point we know that myConverter implements a IMagicConverter
public void TestMethod(Type myConverter, int number, ref object returnvalue)
{
// work out what the generic argument is
var typeArgument = myConverter.GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() == typeof (IMagicConverter<>))
.Select(x => x.GetGenericArguments())
.First();
// cast it to that type
var instance = (IMagicConverter<typeArgument>)Activator.CreateInstance(myConverter);
returnvalue = instance.ConvertIt(number);
}
}
[TestFixture]
public class MyTest
{
[Test]
public void MyStringConverter_ConvertsTheNumberOne_ToEnglish()
{
// Arrange
var test = new TestClass();
object returnValue = null;
// Act
test.TestMethod(typeof(MyStringConverter), 1, ref returnValue);
// Assert
Assert.That(returnValue, Is.EqualTo("Number one"));
}
}
答案 0 :(得分:1)
基本上,你需要在每一步都使用反射 - 你需要通过反射找到你想要的方法,并用反射来调用它。非常难看。
在那一点上,它很容易作弊:
public void TestMethod(Type myConverter, int number, ref object returnvalue)
{
dynamic obj = Activator.CreateInstance(myConverter);
returnvalue = Evil(obj, number);
}
static T Evil<T>(IMagicConverter<T> converter, int input)
{
return converter.ConvertIt(input);
}
这里的诀窍是dynamic
,它让DLR担心所有这些,其优势在于它具有内置的每类型策略缓存,因此您只需支付一次任何反射成本。
另一种常见方法是使用非通用接口,例如:
public interface IMagicConverter
{
object ConvertIt(int input);
}
public interface IMagicConverter<T> : IMagicConverter
{
new T ConvertIt(int input);
}
然后你使用:
var obj = (IMagicConverter)Activator.CreateInstance(myConverter);
returnvalue = obj.ConvertIt(number);
在这里,为了满足接口,您还需要添加:
object IMagicConverter.ConvertIt(int input)
{
return ConvertIt(input);
}
同时MyStringConverter
和MyDateTimeConverter
,将非通用调用转发给通用调用。