这个嵌套类构造函数片段可以应用于泛型类吗?
Posted
技术标签:
【中文标题】这个嵌套类构造函数片段可以应用于泛型类吗?【英文标题】:Can this nested class constructor snippet apply to a generic class? 【发布时间】:2017-03-13 00:35:30 【问题描述】:Here 是一个高度赞成的解决方案,可以轻松地将嵌套类构造函数限制为仅父类。我正在尝试实现这一点,但在包含嵌套 generic 类的父类的上下文中。为了清楚起见,这里是原始的 sn-p:
public class Journal
private static Func<object, JournalEntry> _newJournalEntry;
public class JournalEntry
static JournalEntry()
_newJournalEntry = value => new JournalEntry(value);
private JournalEntry(object value)
...
这是我目前所在的位置(为简单起见,我将 Func<object,JournalEntry>
替换为简单的 Func<JournalEntry>
。)
public class Journal
private static Func<JournalEntry> _new;
public JournalEntry<T> NewJournalEntry<T>()
return (JournalEntry<T>)_new();
public Journal()
public class JournalEntry
public class JournalEntry<T>:JournalEntry
static JournalEntry()
_new = () => new JournalEntry<T>();
private JournalEntry()
这是用例:
Journal j = new Journal();
Journal.JournalEntry<string> stringEntry = j.NewJournalEntry<string>();
//Fails with null reference exception
根据原始 sn-p 的此评论,
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor
可以挽救这一天。 :)
我试了一下:
Journal j = new Journal();
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Journal.JournalEntry<string>).TypeHandle);
Journal.JournalEntry<string> stringEntry = j.NewJournalEntry<string>();
//Passes
上面的代码有效。以下作品:
Journal j = new Journal();
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Journal.JournalEntry<string>).TypeHandle);
Journal.JournalEntry<string> stringEntry = j.NewJournalEntry<string>();
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Journal.JournalEntry<int>).TypeHandle);
Journal.JournalEntry<int> intEntry = j.NewJournalEntry<int>();
但尝试请求另一个 JournalEntry<string>
失败:
附加信息:无法将 JournalEntry[System.Int32] 类型的对象转换为 JournalEntry[System.String] 类型。
我该如何解决这个难题,以便我可以创建任意数量的 JournalEntry<>
的任何类型的实例?
【问题讨论】:
【参考方案1】:您的方法行不通,因为每次 JournalEntry<T>
的类型初始化程序运行(并且每个 T
运行一次)时,它都会覆盖 _new
的先前值,从而破坏未来的使用其他T
s.
相反,您可以这样做:
public class Journal
public JournalEntry<T> NewJournalEntry<T>()
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(JournalEntry<T>).TypeHandle);
return JournalEntryFactory<T>._new();
private static class JournalEntryFactory<T>
public static Func<JournalEntry<T>> _new;
public Journal()
public class JournalEntry
public class JournalEntry<T> : JournalEntry
static JournalEntry()
JournalEntryFactory<T>._new = () => new JournalEntry<T>();
private JournalEntry()
这样,每个T
都有一个单独的_new
。
顺便说一句,我是问你提到的问题的人。对于它的价值,我认为这种方法有点骇人听闻且容易出错。如果可能的话,我强烈建议您使用accepted answer 中的基于接口的方法。以下是您的情况:
public interface IJournalEntry<T>
public class Journal
public IJournalEntry<T> NewJournalEntry<T>()
return new JournalEntry<T>();
public Journal()
private class JournalEntry<T> : IJournalEntry<T>
public JournalEntry()
【讨论】:
使用接口方法的原始接受答案中没有立即显示的一个特定信息:使用 public 构造函数将嵌套类定义 private ,并且奇迹般地只有外部类可以调用构造函数,正如那里的评论者所指出的那样。我可以请求一个最终干净的 sn-p 你是如何使用接口方法的吗?【参考方案2】:您需要多个new
方法。我建议将它们保存在 Dictionary
中,如下所示:
public class Journal
private static Dictionary<Type, Func<JournalEntry>> _newFuncs = new Dictionary<System.Type, System.Func<UserQuery.Journal.JournalEntry>>();
public JournalEntry<T> NewJournalEntry<T>()
var newFunc = _newFuncs[typeof(T)];
return (JournalEntry<T>)newFunc();
public Journal()
public class JournalEntry
public class JournalEntry<T> : JournalEntry
static JournalEntry()
_newFuncs.Add(typeof(T), () => new JournalEntry<T>());
private JournalEntry()
【讨论】:
【参考方案3】:您可以修改您的类,以便将_new
作为字典,这将允许创建多种类型:
public class Journal
private static IDictionary<Type, Func<JournalEntry>> _new = new Dictionary<Type, Func<JournalEntry>>();
public JournalEntry<T> NewJournalEntry<T>()
return (JournalEntry<T>)_new[typeof(T)]();
public Journal()
public class JournalEntry
public class JournalEntry<T> : JournalEntry
static JournalEntry()
_new.Add(typeof(T), () => new JournalEntry<T>());
private JournalEntry()
【讨论】:
【参考方案4】:不能很容易地完全按照您的要求完成(通用类实际上是一组类,因此您需要为_new
提供多个代表,并通过某种方式来选择一个)但这里有一个非常完成您想要的事情的简单方法,无需使用 hacky 静态构造函数和委托,也无需使用单独的接口。
本质上,我们创建了一个受保护的工厂方法,然后使用该方法的公共版本创建该类的私有派生。受保护的工厂方法只能从我们的私有类中调用。
public class Journal
public class JournalEntry
public class JournalEntry<T> : JournalEntry
protected JournalEntry()
static protected JournalEntry<T> NewJournalEntry()
return new JournalEntry<T>();
private class Maker<T> : JournalEntry<T>
new static public JournalEntry<T> NewJournalEntry()
return JournalEntry<T>.NewJournalEntry();
public JournalEntry<T> NewJournalEntry<T>()
return Maker<T>.NewJournalEntry();
然后您可以像这样创建一个新实例(完全按照您的要求):
Journal j = new Journal();
Journal.JournalEntry<string> stringEntry = j.NewJournalEntry<string>();
但是不能直接实例化:
Journal.JournalEntry<string> wontWork = new Journal.JournalEntry<string>(); //is inaccessible due to its protection level
【讨论】:
以上是关于这个嵌套类构造函数片段可以应用于泛型类吗?的主要内容,如果未能解决你的问题,请参考以下文章
c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?