C# 将接口作为参数传递给类构造函数
我正在使用iText7读取PDF文件数据,并根据它们在PDF文件中的位置创建一个xml文件。 我的问题是 iText7程序集中有一个类C# 将接口作为参数传递给类构造函数,c#,.net,itext7,C#,.net,Itext7,我正在使用iText7读取PDF文件数据,并根据它们在PDF文件中的位置创建一个xml文件。 我的问题是 iText7程序集中有一个类LocationTextExtractionStrategy,如下所示 public class LocationTextExtractionStrategy : ITextExtractionStrategy, IEventListener { public LocationTextExtractionStrategy(ITextChunkLocatio
LocationTextExtractionStrategy
,如下所示
public class LocationTextExtractionStrategy : ITextExtractionStrategy, IEventListener
{
public LocationTextExtractionStrategy(ITextChunkLocationStrategy strat);
public virtual void EventOccurred(IEventData data, EventType type);
public interface ITextChunkLocationStrategy
{
ITextChunkLocation CreateLocation(TextRenderInfo renderInfo, LineSegment baseline);
}
}
public class TextLocationExtractionStrategy : LocationTextExtractionStrategy
{
ITextChunkLocationStrategy locationstrategy ;
public TextLocationExtractionStrategy(ITextChunkLocationStrategy strategy)
{
locationstrategy = strategy;
}
public override void EventOccurred(IEventData data, EventType type)
{
if (!type.Equals(EventType.RENDER_TEXT))
return;
TextRenderInfo renderInfo = (TextRenderInfo)data;
string curFont = renderInfo.GetFont().GetFontProgram().ToString();
float curFontSize = renderInfo.GetFontSize();
IList<TextRenderInfo> text = renderInfo.GetCharacterRenderInfos();
foreach (TextRenderInfo t in text)
{
LineSegment lineSegment = t.GetBaseline();
string letter = t.GetText();
Vector letterStart = t.GetBaseline().GetStartPoint();
Vector letterEnd = t.GetAscentLine().GetEndPoint();
Rectangle letterRect = new Rectangle(letterStart.Get(0), letterStart.Get(1),
letterEnd.Get(0) - letterStart.Get(0), letterEnd.Get(1) - letterStart.Get(1));
if (letter != " " && !letter.Contains(' '))
{
ITextChunkLocation loc = locationstrategy.CreateLocation(t, lineSegment);
UTextChunk chunk = new UTextChunk(t, t.GetText(), loc);
t.GetText();
t.GetBaseline().GetBoundingRectangle();
m_locationResult.Add(chunk);
}
}
}
}
现在我将这个类继承到我的项目类中,如下所示
public class LocationTextExtractionStrategy : ITextExtractionStrategy, IEventListener
{
public LocationTextExtractionStrategy(ITextChunkLocationStrategy strat);
public virtual void EventOccurred(IEventData data, EventType type);
public interface ITextChunkLocationStrategy
{
ITextChunkLocation CreateLocation(TextRenderInfo renderInfo, LineSegment baseline);
}
}
public class TextLocationExtractionStrategy : LocationTextExtractionStrategy
{
ITextChunkLocationStrategy locationstrategy ;
public TextLocationExtractionStrategy(ITextChunkLocationStrategy strategy)
{
locationstrategy = strategy;
}
public override void EventOccurred(IEventData data, EventType type)
{
if (!type.Equals(EventType.RENDER_TEXT))
return;
TextRenderInfo renderInfo = (TextRenderInfo)data;
string curFont = renderInfo.GetFont().GetFontProgram().ToString();
float curFontSize = renderInfo.GetFontSize();
IList<TextRenderInfo> text = renderInfo.GetCharacterRenderInfos();
foreach (TextRenderInfo t in text)
{
LineSegment lineSegment = t.GetBaseline();
string letter = t.GetText();
Vector letterStart = t.GetBaseline().GetStartPoint();
Vector letterEnd = t.GetAscentLine().GetEndPoint();
Rectangle letterRect = new Rectangle(letterStart.Get(0), letterStart.Get(1),
letterEnd.Get(0) - letterStart.Get(0), letterEnd.Get(1) - letterStart.Get(1));
if (letter != " " && !letter.Contains(' '))
{
ITextChunkLocation loc = locationstrategy.CreateLocation(t, lineSegment);
UTextChunk chunk = new UTextChunk(t, t.GetText(), loc);
t.GetText();
t.GetBaseline().GetBoundingRectangle();
m_locationResult.Add(chunk);
}
}
}
}
由于我们不能创建接口的实例,我不知道如何将值传递给接口类型的参数。在上面的几行中,我只是将其赋值为null并调用构造函数,但是如果将null值赋值给它,它会说“对象引用未设置为对象的实例”
你能帮我解决这个问题吗
如果在提出我的问题时有任何问题,请告诉我或纠正我。如果您查看基类的源代码
LocationTextExtractionStrategy
(它是开源的,所以请查看源代码!),您将看到它不仅具有带ITextChunkLocationStrategy
参数的构造函数,它也有一个没有参数的构造函数
该构造函数实际实例化了该接口的实现,并将其转发给您引用的同一个构造函数:
public LocationTextExtractionStrategy()
: this(new _ITextChunkLocationStrategy_85()) {
}
private sealed class _ITextChunkLocationStrategy_85 : LocationTextExtractionStrategy.ITextChunkLocationStrategy {
public _ITextChunkLocationStrategy_85() {
}
public ITextChunkLocation CreateLocation(TextRenderInfo renderInfo, LineSegment baseline) {
return new TextChunkLocationDefaultImp(baseline.GetStartPoint(), baseline.GetEndPoint(), renderInfo.GetSingleSpaceWidth());
}
}
由于您希望使用ITextChunkLocationStrategy
实现,而基类不为其提供getter,因此不能简单地使用没有参数的另一个构造函数。您不能实例化这个\u ITextChunkLocationStrategy\u 85
类,因为它是私有的。您不能简单地将\u ITextChunkLocationStrategy\u 85
复制到您的代码中,因为TextChunkLocationDefaultImp
是内部的
但是,您可以做的是将TextChunkLocationDefaultImp
复制到您的代码中,然后将\u ITextChunkLocationStrategy\u 85
复制到您的代码中,使用该类的副本替换基类中使用的TextChunkLocationDefaultImp
,然后实例化\u ITextChunkLocationStrategy\u 85
类的副本,以最终获得ITextChunkLocationStrategy
实现实例
或者,你可以试着进行反思和内省。不过,这可能会导致维护问题
如果一个库提供了泛化某个东西的方法,然后隐藏了它的默认实现,那么这将是一个真正的麻烦
作为参考,TextChunkLocationDefaultImp
当前的实现如下
internal class TextChunkLocationDefaultImp : ITextChunkLocation {
private const float DIACRITICAL_MARKS_ALLOWED_VERTICAL_DEVIATION = 2;
/// <summary>the starting location of the chunk</summary>
private readonly Vector startLocation;
/// <summary>the ending location of the chunk</summary>
private readonly Vector endLocation;
/// <summary>unit vector in the orientation of the chunk</summary>
private readonly Vector orientationVector;
/// <summary>the orientation as a scalar for quick sorting</summary>
private readonly int orientationMagnitude;
/// <summary>perpendicular distance to the orientation unit vector (i.e.</summary>
/// <remarks>
/// perpendicular distance to the orientation unit vector (i.e. the Y position in an unrotated coordinate system)
/// we round to the nearest integer to handle the fuzziness of comparing floats
/// </remarks>
private readonly int distPerpendicular;
/// <summary>distance of the start of the chunk parallel to the orientation unit vector (i.e.</summary>
/// <remarks>distance of the start of the chunk parallel to the orientation unit vector (i.e. the X position in an unrotated coordinate system)
/// </remarks>
private readonly float distParallelStart;
/// <summary>distance of the end of the chunk parallel to the orientation unit vector (i.e.</summary>
/// <remarks>distance of the end of the chunk parallel to the orientation unit vector (i.e. the X position in an unrotated coordinate system)
/// </remarks>
private readonly float distParallelEnd;
/// <summary>the width of a single space character in the font of the chunk</summary>
private readonly float charSpaceWidth;
public TextChunkLocationDefaultImp(Vector startLocation, Vector endLocation, float charSpaceWidth) {
this.startLocation = startLocation;
this.endLocation = endLocation;
this.charSpaceWidth = charSpaceWidth;
Vector oVector = endLocation.Subtract(startLocation);
if (oVector.Length() == 0) {
oVector = new Vector(1, 0, 0);
}
orientationVector = oVector.Normalize();
orientationMagnitude = (int)(Math.Atan2(orientationVector.Get(Vector.I2), orientationVector.Get(Vector.I1)
) * 1000);
// see http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
// the two vectors we are crossing are in the same plane, so the result will be purely
// in the z-axis (out of plane) direction, so we just take the I3 component of the result
Vector origin = new Vector(0, 0, 1);
distPerpendicular = (int)(startLocation.Subtract(origin)).Cross(orientationVector).Get(Vector.I3);
distParallelStart = orientationVector.Dot(startLocation);
distParallelEnd = orientationVector.Dot(endLocation);
}
public virtual int OrientationMagnitude() {
return orientationMagnitude;
}
public virtual int DistPerpendicular() {
return distPerpendicular;
}
public virtual float DistParallelStart() {
return distParallelStart;
}
public virtual float DistParallelEnd() {
return distParallelEnd;
}
/// <returns>the start location of the text</returns>
public virtual Vector GetStartLocation() {
return startLocation;
}
/// <returns>the end location of the text</returns>
public virtual Vector GetEndLocation() {
return endLocation;
}
/// <returns>the width of a single space character as rendered by this chunk</returns>
public virtual float GetCharSpaceWidth() {
return charSpaceWidth;
}
/// <param name="as">the location to compare to</param>
/// <returns>true is this location is on the the same line as the other</returns>
public virtual bool SameLine(ITextChunkLocation @as) {
if (OrientationMagnitude() != @as.OrientationMagnitude()) {
return false;
}
float distPerpendicularDiff = DistPerpendicular() - @as.DistPerpendicular();
if (distPerpendicularDiff == 0) {
return true;
}
LineSegment mySegment = new LineSegment(startLocation, endLocation);
LineSegment otherSegment = new LineSegment(@as.GetStartLocation(), @as.GetEndLocation());
return Math.Abs(distPerpendicularDiff) <= DIACRITICAL_MARKS_ALLOWED_VERTICAL_DEVIATION && (mySegment.GetLength
() == 0 || otherSegment.GetLength() == 0);
}
/// <summary>
/// Computes the distance between the end of 'other' and the beginning of this chunk
/// in the direction of this chunk's orientation vector.
/// </summary>
/// <remarks>
/// Computes the distance between the end of 'other' and the beginning of this chunk
/// in the direction of this chunk's orientation vector. Note that it's a bad idea
/// to call this for chunks that aren't on the same line and orientation, but we don't
/// explicitly check for that condition for performance reasons.
/// </remarks>
/// <param name="other"/>
/// <returns>the number of spaces between the end of 'other' and the beginning of this chunk</returns>
public virtual float DistanceFromEndOf(ITextChunkLocation other) {
return DistParallelStart() - other.DistParallelEnd();
}
public virtual bool IsAtWordBoundary(ITextChunkLocation previous) {
// In case a text chunk is of zero length, this probably means this is a mark character,
// and we do not actually want to insert a space in such case
if (startLocation.Equals(endLocation) || previous.GetEndLocation().Equals(previous.GetStartLocation())) {
return false;
}
float dist = DistanceFromEndOf(previous);
if (dist < 0) {
dist = previous.DistanceFromEndOf(this);
//The situation when the chunks intersect. We don't need to add space in this case
if (dist < 0) {
return false;
}
}
return dist > GetCharSpaceWidth() / 2.0f;
}
internal static bool ContainsMark(ITextChunkLocation baseLocation, ITextChunkLocation markLocation) {
return baseLocation.GetStartLocation().Get(Vector.I1) <= markLocation.GetStartLocation().Get(Vector.I1) &&
baseLocation.GetEndLocation().Get(Vector.I1) >= markLocation.GetEndLocation().Get(Vector.I1) && Math.
Abs(baseLocation.DistPerpendicular() - markLocation.DistPerpendicular()) <= DIACRITICAL_MARKS_ALLOWED_VERTICAL_DEVIATION;
}
}
内部类TextChunkLocationDefaultImp:ITextChunkLocation{
私有常量浮点变音符号允许的垂直偏差=2;
///块的起始位置
私有只读向量定位;
///块的结束位置
专用只读向量结束位置;
///块方向上的单位向量
私有只读向量方向向量;
///用于快速排序的标量方向
私有只读int方向大小;
///与方向单位向量的垂直距离(即。
///
///与方向单位向量的垂直距离(即未旋转坐标系中的Y位置)
///我们四舍五入到最接近的整数来处理比较浮点数的模糊性
///
私有只读int;
///平行于方向单位向量的块起点距离(即。
///平行于方向单位向量的块起点距离(即未旋转坐标系中的X位置)
///
私有只读浮点启动;
///平行于方向单位向量的块端距离(即。
///平行于方向单位向量的块端距离(即未旋转坐标系中的X位置)
///
私有只读浮点数;
///块字体中单个空格字符的宽度
私有只读浮点字符空间宽度;
public TextChunkLocationDefaultImp(向量位置、向量结束位置、浮点字符空间宽度){
this.startolocation=startolocation;
this.endLocation=endLocation;
this.charSpaceWidth=charSpaceWidth;
向量向量向量=结束位置。减去(起始位置);
如果(oVector.Length()==0){
oVector=新向量(1,0,0);
}
方向向量=oVector.Normalize();
orientationmagnity=(int)(Math.Atan2(orientationVector.Get(Vector.I2),orientationVector.Get(Vector.I1)
) * 1000);
//看http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
//我们相交的两个向量在同一个平面上,因此结果将完全相同
//在z轴(平面外)方向,我们只取结果的I3分量
向量原点=新向量(0,0,1);
distvertical=(int)(起始位置。减去(原点))。交叉(方向向量)。获取(向量。I3);
distParallelStart=方向向量.Dot(位置);
distParallelEnd=方向向量.Dot(endLocation);
}
公共虚拟int方向重要性(){
返回方向大小;
}
公共虚拟整数(){
返回垂直;
}
公共虚拟浮点数开始(){
返回并启动;
}
公共虚拟浮点数(){
返回端;
}
///文本的起始位置
公共虚拟向量{
返回定位;
}
///文本的结束位置
公共虚拟向量GetEndLocation(){
返回端定位;
}
///此块渲染的单个空格字符的宽度
公共虚拟浮点GetCharSpaceWidth(){
返回字符空间宽度;
}
///指向com的位置