如何在C#中使用参数化构造函数创建generics类型参数的实例

我正在尝试编写一个帮助器方法,该方法将记录消息并使用相同的消息抛出指定类型的exception。 我有以下内容:

private void LogAndThrow(string message, params object[] args) where TException : Exception, new() { message = string.Format(message, args); Logger.Error(message); throw new TException(message); } 

在添加new()约束之前,编译器抱怨说没有它我就无法实例化TException 。 现在我收到的错误消息是“在创建类型参数’TException’的实例时无法提供参数”。 我尝试使用无参数构造函数创建实例,然后设置Message属性,但它是只读的。

这是语言的限制还是我不知道的解决方案? 也许我可以使用reflection,但这对于这么简单的任务来说太过分了。 (而且非常丑陋,但这是个人观点的问题。)

您可以使用Activator.CreateInstance() (允许您传入参数)来创建TException的实例。 然后,您可以抛出创建的TException

例如:

 private void LogAndThrow(string message, params object[] args) where TException : Exception, new() { message = string.Format(message, args); Logger.Error(message); TException exception = (TException)Activator.CreateInstance(typeof(TException), message); throw exception; } 

是的,这是一个限制; 没有语言构造。

我在这种情况下的建议是为每个类型的构造函数创建一个类型化的委托; 缓存该委托(为方便起见,通常在generics类型的静态字段中)并重新使用它。 我可以稍后提供一个例子 – 但我不能从iPod做到这一点;)

相信我已经为Jon Skeet的MiscUtil库提供了一些代码; 所以你也可以看一下


根据要求(评论),这是一种方法 – 在这种情况下使用Expression API。 特别注意嵌套generics类的使用,确保我们每个类型组合最多进行一次reflection/编译:

 using System; using System.Linq.Expressions; class Program { static void Main() { var ctor = TypeFactory.GetCtor(); var obj = ctor(123, "abc"); Console.WriteLine(obj.I); Console.WriteLine(obj.S); } } class DemoType { public int I { get; private set; } public string S { get; private set; } public DemoType(int i, string s) { I = i; S = s; } } static class TypeFactory { public static Func GetCtor() { return Cache.func; } public static Func GetCtor() { return Cache.func; } public static Func GetCtor() { return Cache.func; } private static Delegate CreateConstructor(Type type, params Type[] args) { if(type == null) throw new ArgumentNullException("type"); if(args == null) args = Type.EmptyTypes; ParameterExpression[] @params = Array.ConvertAll(args, Expression.Parameter); return Expression.Lambda(Expression.New(type.GetConstructor(args), @params), @params).Compile(); } private static class Cache { public static readonly Func func = (Func)TypeFactory.CreateConstructor(typeof(T)); } private static class Cache { public static readonly Func func = (Func)TypeFactory.CreateConstructor(typeof(T), typeof(TArg1)); } private static class Cache { public static readonly Func func = (Func)TypeFactory.CreateConstructor(typeof(T), typeof(TArg1), typeof(TArg2)); } } 

这是通用约束new限制。 它只能用于通过无参数构造函数创建对象。

解决此问题的一种方法是提供采用适当参数的lambda工厂方法。 在调用站点,它可以遵循类构造函数

 private void LogAndThrow( Func func, string message, params object[] args) where TException : Exception { message = string.Format(message, args); Logger.Error(message); throw func(message); } LogAndThrow(msg => new InvalidOperationException(msg), "my message"); 

试试这个

 private void ThrowAndLog(string message, params object[] args) where TException : Exception, new() { message = string.Format(message, args); Logger.Error(message); throw (TException)typeof(TException).GetConstructor( new[] { typeof(string) }).Invoke(new object[] { message }); }