PLY 文件行的更通用的 TryParse()
More generic TryParse() of line of a PLY file
我正在构建一个导入函数以将 PLY File 加载到我的程序中。我不确定的部分是 Face-Parser 的实现。这样的脸可能有两个不同的版本,Face3(连接 3 个顶点)或 Face4(连接 4 个顶点)。在 *.ply 文件中,它们可能如下所示:
面 3:
3 0 1 2 3
面 4:
4 0 1 2 3
我为它们创建了一个class,实现了接口IFace
。但是,该接口无法定义方法 TryParse()
,因为我希望它是静态的。所以每个 Face
classes 都实现了他们自己的 TryParse
方法和一个额外的 TryParse
到 return 一个 IFace
而不是 Face3
或 Face4
。从几点来看,这些方法大多是相同的。目前 TryParse
的实现方式(2 种不同的 classes 中的 2 种方法)感觉非常笨拙。有没有更好的方法来解决这个问题?
这就是我目前的使用方式:
foreach (string line in faceLines)
{
IFace face = new Face3(); // ugly: I need to instanciate the face bevore I can use "out face"
var segments = lines[i].Split(' '); // ugly: I'd rather not touch the line at all. TryParse should do everything
switch (segments[0]) // ugly!
{
case "3":
if (Face3.TryParse(lines[i], out face)) faces.Add((Face4)face);
break;
case "4":
if (Face4.TryParse(lines[i], out face)) faces.Add((Face4)face);
break;
}
}
这里是 IFace
、Face3
和 Face4
:
public interface IFace
{
string ToString();
}
public struct Face3 : IFace
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
internal static bool TryParse(string Input, out IFace Face)
{
Face3 face = new Face3();
bool b = TryParse(Input, out face);
Face = (IFace)face;
return b;
}
internal static bool TryParse(string Input, out Face3 Face)
{
Face = new Face3();
var args = Input.Split(' ');
if (args.Length != 4) return false;
bool success = true;
success = success && int.TryParse(args[1], out Face.V1);
success = success && int.TryParse(args[2], out Face.V2);
success = success && int.TryParse(args[3], out Face.V3);
if (!success) return false;
return true;
}
}
public struct Face4 : IFace
{
public int V1;
public int V2;
public int V3;
public int V4;
public override string ToString()
{
return string.Format("4 {0} {1} {2} {3}", V1, V2, V3, V4);
}
internal static bool TryParse(string Input, out IFace Face)
{
Face4 face = new Face4();
bool b = TryParse(Input, out face);
Face = (IFace)face;
return b;
}
internal static bool TryParse(string Input, out Face4 Face)
{
Face = new Face4();
var args = Input.Split(' ');
if (args.Length != 5) return false;
bool success = true;
success = success && int.TryParse(args[1], out Face.V1);
success = success && int.TryParse(args[2], out Face.V2);
success = success && int.TryParse(args[3], out Face.V3);
success = success && int.TryParse(args[4], out Face.V4);
if (!success) return false;
return true;
}
}
更新: 根据@Heslacher 的回答,我实施了一些更改。由于我希望能够直接调用 Face.TryParse
而无需 FaceParser
class,我将接口 IFace
更改为抽象 class Face
.因此 Face3
和 Face4
现在不再是 struct
而是 class
。我对解决方案非常满意。
正在解析人脸:
Face face;
if (Face.TryParse(lines[i], out face))
{
faces.Add(face);
}
与:
public abstract class Face
{
public static bool TryParse(string line, out Face face)
{
if (Face3.TryParse(line, out face)) { return true; }
if (Face4.TryParse(line, out face)) { return true; }
return false;
}
}
public class Face3 : Face
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
new internal static bool TryParse(string input, out Face face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 4) return false;
Face3 parsedFace = new Face3();
bool success = true;
success = success && int.TryParse(args[1], out parsedFace.V1);
success = success && int.TryParse(args[2], out parsedFace.V2);
success = success && int.TryParse(args[3], out parsedFace.V3);
if (!success) return false;
face = parsedFace;
return true;
}
}
public class Face4 : Face
{
public int V1;
public int V2;
public int V3;
public int V4;
public override string ToString()
{
return string.Format("4 {0} {1} {2} {3}", V1, V2, V3, V4);
}
new internal static bool TryParse(string input, out Face face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 5) return false;
Face4 parsedFace = new Face4();
bool success = true;
success = success && int.TryParse(args[1], out parsedFace.V1);
success = success && int.TryParse(args[2], out parsedFace.V2);
success = success && int.TryParse(args[3], out parsedFace.V3);
success = success && int.TryParse(args[4], out parsedFace.V4);
if (!success) return false;
face = parsedFace;
return true;
}
}
免责声明: 所以这更像是一次代码审查(你已经删除了你的问题 http://codereview.stackexchange.com),但它应该解决你的问题。
基于 nameing guidelines 输入参数应使用 camelCase
大小写命名。
我看不出为什么您为 Face3
和 Face4
重载了 TryParse()
方法。
设置传递的输入参数 face
(命名准则)= null
可以在不向参数分配任何新对象的情况下提前 return。
按照您创建新 Face3
的方式,如果 TryParse()
returned false
,传入的 IFace
也会被初始化。
这个
public struct Face3 : IFace
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
internal static bool TryParse(string input, out IFace face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 4)
{
return false;
}
Face3 currentFace = new Face3();
bool success = true;
success=success && int.TryParse(args[1], out currentFace.V1);
success = success && int.TryParse(args[2], out currentFace.V2);
success = success && int.TryParse(args[3], out currentFace.V3);
if (!success)
{
return false;
}
face = currentFace;
return true;
}
}
会正常工作,即使没有这个
IFace face = new Face3(); // ugly: I need to instanciate the face bevore I can use "out face"
通过添加一个可以是私有的 FaceParser
class 和一个像
这样的静态 TryParse()
方法
private class FaceParser
{
public static bool TryParse(string line, out IFace face)
{
if (Face3.TryParse(line, out face)) { return true; }
if (Face4.TryParse(line, out face)) { return true; }
return false;
}
}
如果它是私有的,则应包含在要添加到面孔的 class 中,您如何解析线条的初始示例可以简化为
foreach (string line in faceLines)
{
IFace face;
if (FaceParser.TryParse(line, out face))
{
faces.Add(face);
}
}
看来你只是把IFace
接口当做一个标记接口。向接口添加 ToString()
方法在某种程度上是多余的,因为每个对象都已经包含一个可覆盖的 ToString()
方法。因此,您可以将界面简化为
public interface IFace {}
正常 解析器将处理所有标记,从第一个开始,让控制流由读取的标记决定。
在您的情况下,(全局)解析器将读取第一个 int,然后决定它是否继续代码的 "face3" 或 "face4" 部分,在途中读取更多 int 和 return Face3
或行尾的 Face4
实例。
因此,此类解析器的一般概要是:
getNextToken();
switch(currentToken)
{
case Face3Start:
getface3();
break;
case Face4Start:
getface4();
break;
}
我正在构建一个导入函数以将 PLY File 加载到我的程序中。我不确定的部分是 Face-Parser 的实现。这样的脸可能有两个不同的版本,Face3(连接 3 个顶点)或 Face4(连接 4 个顶点)。在 *.ply 文件中,它们可能如下所示:
面 3:
3 0 1 2 3
面 4:
4 0 1 2 3
我为它们创建了一个class,实现了接口IFace
。但是,该接口无法定义方法 TryParse()
,因为我希望它是静态的。所以每个 Face
classes 都实现了他们自己的 TryParse
方法和一个额外的 TryParse
到 return 一个 IFace
而不是 Face3
或 Face4
。从几点来看,这些方法大多是相同的。目前 TryParse
的实现方式(2 种不同的 classes 中的 2 种方法)感觉非常笨拙。有没有更好的方法来解决这个问题?
这就是我目前的使用方式:
foreach (string line in faceLines)
{
IFace face = new Face3(); // ugly: I need to instanciate the face bevore I can use "out face"
var segments = lines[i].Split(' '); // ugly: I'd rather not touch the line at all. TryParse should do everything
switch (segments[0]) // ugly!
{
case "3":
if (Face3.TryParse(lines[i], out face)) faces.Add((Face4)face);
break;
case "4":
if (Face4.TryParse(lines[i], out face)) faces.Add((Face4)face);
break;
}
}
这里是 IFace
、Face3
和 Face4
:
public interface IFace
{
string ToString();
}
public struct Face3 : IFace
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
internal static bool TryParse(string Input, out IFace Face)
{
Face3 face = new Face3();
bool b = TryParse(Input, out face);
Face = (IFace)face;
return b;
}
internal static bool TryParse(string Input, out Face3 Face)
{
Face = new Face3();
var args = Input.Split(' ');
if (args.Length != 4) return false;
bool success = true;
success = success && int.TryParse(args[1], out Face.V1);
success = success && int.TryParse(args[2], out Face.V2);
success = success && int.TryParse(args[3], out Face.V3);
if (!success) return false;
return true;
}
}
public struct Face4 : IFace
{
public int V1;
public int V2;
public int V3;
public int V4;
public override string ToString()
{
return string.Format("4 {0} {1} {2} {3}", V1, V2, V3, V4);
}
internal static bool TryParse(string Input, out IFace Face)
{
Face4 face = new Face4();
bool b = TryParse(Input, out face);
Face = (IFace)face;
return b;
}
internal static bool TryParse(string Input, out Face4 Face)
{
Face = new Face4();
var args = Input.Split(' ');
if (args.Length != 5) return false;
bool success = true;
success = success && int.TryParse(args[1], out Face.V1);
success = success && int.TryParse(args[2], out Face.V2);
success = success && int.TryParse(args[3], out Face.V3);
success = success && int.TryParse(args[4], out Face.V4);
if (!success) return false;
return true;
}
}
更新: 根据@Heslacher 的回答,我实施了一些更改。由于我希望能够直接调用 Face.TryParse
而无需 FaceParser
class,我将接口 IFace
更改为抽象 class Face
.因此 Face3
和 Face4
现在不再是 struct
而是 class
。我对解决方案非常满意。
正在解析人脸:
Face face;
if (Face.TryParse(lines[i], out face))
{
faces.Add(face);
}
与:
public abstract class Face
{
public static bool TryParse(string line, out Face face)
{
if (Face3.TryParse(line, out face)) { return true; }
if (Face4.TryParse(line, out face)) { return true; }
return false;
}
}
public class Face3 : Face
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
new internal static bool TryParse(string input, out Face face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 4) return false;
Face3 parsedFace = new Face3();
bool success = true;
success = success && int.TryParse(args[1], out parsedFace.V1);
success = success && int.TryParse(args[2], out parsedFace.V2);
success = success && int.TryParse(args[3], out parsedFace.V3);
if (!success) return false;
face = parsedFace;
return true;
}
}
public class Face4 : Face
{
public int V1;
public int V2;
public int V3;
public int V4;
public override string ToString()
{
return string.Format("4 {0} {1} {2} {3}", V1, V2, V3, V4);
}
new internal static bool TryParse(string input, out Face face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 5) return false;
Face4 parsedFace = new Face4();
bool success = true;
success = success && int.TryParse(args[1], out parsedFace.V1);
success = success && int.TryParse(args[2], out parsedFace.V2);
success = success && int.TryParse(args[3], out parsedFace.V3);
success = success && int.TryParse(args[4], out parsedFace.V4);
if (!success) return false;
face = parsedFace;
return true;
}
}
免责声明: 所以这更像是一次代码审查(你已经删除了你的问题 http://codereview.stackexchange.com),但它应该解决你的问题。
基于 nameing guidelines 输入参数应使用 camelCase
大小写命名。
我看不出为什么您为 Face3
和 Face4
重载了 TryParse()
方法。
设置传递的输入参数 face
(命名准则)= null
可以在不向参数分配任何新对象的情况下提前 return。
按照您创建新 Face3
的方式,如果 TryParse()
returned false
,传入的 IFace
也会被初始化。
这个
public struct Face3 : IFace
{
public int V1;
public int V2;
public int V3;
public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}
internal static bool TryParse(string input, out IFace face)
{
face = null;
var args = input.Split(' ');
if (args.Length != 4)
{
return false;
}
Face3 currentFace = new Face3();
bool success = true;
success=success && int.TryParse(args[1], out currentFace.V1);
success = success && int.TryParse(args[2], out currentFace.V2);
success = success && int.TryParse(args[3], out currentFace.V3);
if (!success)
{
return false;
}
face = currentFace;
return true;
}
}
会正常工作,即使没有这个
IFace face = new Face3(); // ugly: I need to instanciate the face bevore I can use "out face"
通过添加一个可以是私有的 FaceParser
class 和一个像
TryParse()
方法
private class FaceParser
{
public static bool TryParse(string line, out IFace face)
{
if (Face3.TryParse(line, out face)) { return true; }
if (Face4.TryParse(line, out face)) { return true; }
return false;
}
}
如果它是私有的,则应包含在要添加到面孔的 class 中,您如何解析线条的初始示例可以简化为
foreach (string line in faceLines)
{
IFace face;
if (FaceParser.TryParse(line, out face))
{
faces.Add(face);
}
}
看来你只是把IFace
接口当做一个标记接口。向接口添加 ToString()
方法在某种程度上是多余的,因为每个对象都已经包含一个可覆盖的 ToString()
方法。因此,您可以将界面简化为
public interface IFace {}
正常 解析器将处理所有标记,从第一个开始,让控制流由读取的标记决定。
在您的情况下,(全局)解析器将读取第一个 int,然后决定它是否继续代码的 "face3" 或 "face4" 部分,在途中读取更多 int 和 return Face3
或行尾的 Face4
实例。
因此,此类解析器的一般概要是:
getNextToken();
switch(currentToken)
{
case Face3Start:
getface3();
break;
case Face4Start:
getface4();
break;
}