我正在尝试制作一个简单的IoC框架。
我想制作一个映射函数,从T
到T
的实例作为其中的一部分 - get<T>
。
get<T>()=new Mock<T>() if T is NOT a Func
get<T>()=()=>new Mock<R>() if T is a Func<R>
get<T>()=(P1)=>new Mock<R>(P1) if T is a Func<P1,R>
get<T>()=(P1,P2)=>new Mock<R>(P1,P2) if T is a Func<P1,P2,R>
//etc.
我写了以下代码:
public override Maybe<T> get<T>()
{
return (T)get_default_unit_testing_definition<T>();
}
Object get_default_unit_testing_definition<T>() where T :class
{
Type type = typeof(T);
if (!type.IsGenericType)
return new Mock<T>();
Type generic = type.GetGenericTypeDefinition();
Type return_type = type.GetGenericArguments().Last();
Type mock_type_definition = typeof(Mock<>);
var concrete_mock_definition = mock_type_definition.MakeGenericType(return_type);
if (generic == typeof(Func<>))
{
return () => Activator.CreateInstance(concrete_mock_definition);
}
else if (generic == typeof(Func<,>))
{
return p1 => Activator.CreateInstance(concrete_mock_definition, p1);
}
//...
return new Mock<T>();
}
但编译器回复我:
cannot convert lambda expression to type "object" because it's not a delegate type
它是.NET 3.5,所以我没有dynamic
个关键字。
将lambda分配给var
也是不可能的。
如何归还这些lambdas?
答案 0 :(得分:1)
稍微摆弄一下,我觉得这对你有用 如果类型不是Func,则GetMock方法将返回Mock 否则它将返回一个Func&gt;如果类型是Func
public abstract class IMockMe
{
private readonly string _a;
private readonly string _b;
public IMockMe()
{
}
public IMockMe(string a, string b)
{
_a = a;
_b = b;
}
public override string ToString()
{
return _a + " " + _b;
}
}
class Program
{
static void Main(string[] args)
{
var mock = GetMock(typeof(IMockMe));
Console.WriteLine(mock);
var func = GetMock(typeof(Func<string, string, IMockMe>));
Console.WriteLine(func);
var del = (Delegate)func;
mock = del.DynamicInvoke("try", "me");
Console.WriteLine(mock);
new Mock<IMockMe>();
Console.ReadLine();
}
private static readonly Regex FuncRegex = new Regex(@"^System.Func`\d+$");
public static object GetMock(Type type)
{
var mt = typeof(Mock<>);
if (type.IsGenericType && FuncRegex.IsMatch(type.GetGenericTypeDefinition().FullName))
{
var args = type.GetGenericArguments();
var returnType = args.Last();
mt = mt.MakeGenericType(returnType);
args = args.Take(args.Length - 1).ToArray();
var parameters = new List<ParameterExpression>();
for (var i = 0; i < args.Length; i++)
{
var name = "P" + i;
var arg = args[i];
parameters.Add(Expression.Parameter(arg, name));
}
var array = Expression.NewArrayInit(typeof(object), parameters.Select(x => (Expression)x).ToArray());
var ci = mt.GetConstructor(new[] {typeof (object[])});
var constructor = Expression.New(ci, array);
var methods = typeof(Expression).GetMethods();
var method = (from m in methods
where m.Name == "Lambda"
let ps = m.GetParameters()
where ps.Length == 2
where ps[0].ParameterType == typeof(Expression)
where ps[1].ParameterType == typeof(ParameterExpression[])
select m)
.First();
var funcType = GetFuncType(mt, args);
method = method.MakeGenericMethod(funcType);
var expression = (Expression)method.Invoke(null, new object[] { constructor, parameters.ToArray() });
var compile = expression.GetType().GetMethod("Compile");
return compile.Invoke(expression, new object[0]);
}
mt = mt.MakeGenericType(type);
return (Mock) Activator.CreateInstance(mt);
}
private static Type GetFuncType(Type mt, Type[] args)
{
Type result;
switch (args.Length)
{
case 0:
result = typeof(Func<>);
break;
case 1:
result = typeof(Func<,>);
break;
case 2:
result = typeof(Func<,,>);
break;
case 3:
result = typeof(Func<,,,>);
break;
case 4:
result = typeof(Func<,,,,>);
break;
case 5:
result = typeof(Func<,,,,,>);
break;
default: throw new ArgumentOutOfRangeException("args");
}
var list = args.ToList();
list.Add(mt);
return result.MakeGenericType(list.ToArray());
}
}
希望这就是你要找的东西:)
答案 1 :(得分:0)
我可能误解了我的任务。如果使用Moq Framework,则映射应为
get<T>()=new Mock<T>().Object if T is NOT a Func
get<T>()=()=>new Mock<R>().Object if T is a Func<R>
get<T>()=(P1)=>new Mock<R>(P1).Object if T is a Func<P1,R>
get<T>()=(P1,P2)=>new Mock<R>(P1,P2).Object if T is a Func<P1,P2,R>
由于Mock<T>
本身不是T
。
我写的解决方案是:编辑原始解决方案非常糟糕,并且没有使用具有参数的构造函数。更新了它。
public partial class MocksProvider : ImplementationProvider
{
static MethodInfo[] method_mocks = typeof(MocksProvider)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.Where(m => m.Name == "func_mock" || m.Name == "action_mock")
.ToArray();
static Dictionary<Type, Object> cache = new Dictionary<Type, object>();
public override Maybe<T> get<T>()
{
if (cache.ContainsKey(typeof(T)))
{
return (T)cache[typeof(T)];
}
T res=null;
try_mock_as_method(ref res);
if(res==null)
{
res = new Mock<T>().Object;
}
cache.Add(typeof(T),res);
return res;
}
static void try_mock_as_method<T>(ref T target)
{
Type type = typeof(T);
if (type == typeof(Action))
{
Action action = () => { };
target = (T)(Object)action;
return;
}
if (!type.IsGenericType)
{
return;
}
Type[] generic_args = type.GetGenericArguments();
Type type_definition = type.GetGenericTypeDefinition();
foreach (MethodInfo mock_generator in method_mocks)
{
Type generator_return_type = mock_generator.ReturnType.GetGenericTypeDefinition();
if (type_definition == generator_return_type)
{
target = (T)mock_generator.MakeGenericMethod(generic_args).Invoke(null, new object[] { });
return;
}
}
}
static Func<T> func_mock<T>() where T : class
{
return () => new Mock<T>().Object;
}
static Func<P1, T> func_mock<P1, T>() where T : class
{
return (p1) => new Mock<T>(p1).Object;
}
static Func<P1, P2, T> func_mock<P1, P2, T>() where T : class
{
return (p1, p2) => new Mock<T>(p1, p2).Object;
}
static Func<P1, P2, P3, T> func_mock<P1, P2, P3, T>() where T : class
{
return (p1, p2, p3) => new Mock<T>(p1, p2, p3).Object;
}
static Func<P1, P2, P3, P4, T> func_mock<P1, P2, P3, P4, T>() where T : class
{
return (p1, p2, p3, p4) => new Mock<T>(p1, p2, p3, p4).Object;
}
static Action<P1> action_mock<P1>()
{
return (p1) => { };
}
static Action<P1, P2> action_mock<P1, P2>()
{
return (p1, p2) => { };
}
static Action<P1, P2, P3> action_mock<P1, P2, P3>()
{
return (p1, p2, p3) => { };
}
static Action<P1, P2, P3, P4> action_mock<P1, P2, P3, P4>()
{
return (p1, p2, p3, p4) => { };
}
}
如果您的框架中Mock<T>
为T
,那么您应该将generic_args
的最后一个元素替换为类型concrete_mock_definition
并使用
new[] { Activator.CreateInstance(concrete_mock_definition)}
而不是mirror_args