这两种方法之间的性能差异应该可以忽略不计。就个人而言,我建议使用非静态方法,因为它提供了灵活性。如果您发现将大部分解析逻辑合并到一个位置很有帮助,则可以使用组合方法(在下面的示例中进行了演示)。
关于性能,如果您在短时间内重复创建 Parser 类的许多新实例,您可能会注意到对性能的影响很小,但是您可能能够重构代码以避免重复创建解析器类。此外,虽然调用实例方法(尤其是虚拟方法)在技术上不如调用静态方法快,但性能差异应该可以忽略不计。
McWafflestix 提出了一个关于状态的好观点。但是,鉴于您当前的实现使用静态方法,我假设您的 Parser 类不需要在调用 Read 方法之间维护状态,因此您应该能够重用同一个 Parser 实例来解析来自BinaryReader 流。
下面是一个示例,说明了我可能会针对此问题采取的方法。以下是此示例的一些特点:
- 使用多态性来抽象有关解析逻辑驻留在给定类型对象的位置的详细信息。
- 使用存储库来存储 Parser 实例,以便它们可以重复使用。
- 使用反射来识别给定类或结构的解析逻辑。
请注意,我将解析逻辑保存在 ParseHelper 类中的静态方法中,MyObjectAParser 和 MyObjectBParser 类上的 Read 实例方法利用 ParseHelper 类上的这些静态方法。这只是一个设计决策,您可以根据如何组织解析逻辑对您最有意义。我猜想将一些特定于类型的解析逻辑移动到单独的 Parser 类中可能是有意义的,但将一些通用解析逻辑保留在 ParseHelper 类中。
// define a non-generic parser interface so that we can refer to all types of parsers
public interface IParser
{
object Read(BinaryReader reader);
}
// define a generic parser interface so that we can specify a Read method specific to a particular type
public interface IParser<T> : IParser
{
new T Read(BinaryReader reader);
}
public abstract class Parser<T> : IParser<T>
{
public abstract T Read(BinaryReader reader);
object IParser.Read(BinaryReader reader)
{
return this.Read(reader);
}
}
// define a Parser attribute so that we can easily determine the correct parser for a given type
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
public class ParserAttribute : Attribute
{
public Type ParserType { get; private set; }
public ParserAttribute(Type parserType)
{
if (!typeof(IParser).IsAssignableFrom(parserType))
throw new ArgumentException(string.Format("The type [{0}] does not implement the IParser interface.", parserType.Name), "parserType");
this.ParserType = parserType;
}
public ParserAttribute(Type parserType, Type targetType)
{
// check that the type represented by parserType implements the IParser interface
if (!typeof(IParser).IsAssignableFrom(parserType))
throw new ArgumentException(string.Format("The type [{0}] does not implement the IParser interface.", parserType.Name), "parserType");
// check that the type represented by parserType implements the IParser<T> interface, where T is the type specified by targetType
if (!typeof(IParser<>).MakeGenericType(targetType).IsAssignableFrom(parserType))
throw new ArgumentException(string.Format("The type [{0}] does not implement the IParser<{1}> interface.", parserType.Name, targetType.Name), "parserType");
this.ParserType = parserType;
}
}
// let's define a couple of example classes for parsing
// the MyObjectA class corresponds to ParseObject1 in the original question
[Parser(typeof(MyObjectAParser))] // the parser type for MyObjectA is MyObjectAParser
class MyObjectA
{
// ...
}
// the MyObjectB class corresponds to ParseObject2 in the original question
[Parser(typeof(MyObjectAParser))] // the parser type for MyObjectB is MyObjectBParser
class MyObjectB
{
// ...
}
// a static class that contains helper functions to handle parsing logic
static class ParseHelper
{
public static MyObjectA ReadObjectA(BinaryReader reader)
{
// <code here to parse MyObjectA from BinaryReader>
throw new NotImplementedException();
}
public static MyObjectB ReadObjectB(BinaryReader reader)
{
// <code here to parse MyObjectB from BinaryReader>
throw new NotImplementedException();
}
}
// a parser class that parses objects of type MyObjectA from a BinaryReader
class MyObjectAParser : Parser<MyObjectA>
{
public override MyObjectA Read(BinaryReader reader)
{
return ParseHelper.ReadObjectA(reader);
}
}
// a parser class that parses objects of type MyObjectB from a BinaryReader
class MyObjectBParser : Parser<MyObjectB>
{
public override MyObjectB Read(BinaryReader reader)
{
return ParseHelper.ReadObjectB(reader);
}
}
// define a ParserRepository to encapsulate the logic for finding the correct parser for a given type
public class ParserRepository
{
private Dictionary<Type, IParser> _Parsers = new Dictionary<Type, IParser>();
public IParser<T> GetParser<T>()
{
// attempt to look up the correct parser for type T from the dictionary
Type targetType = typeof(T);
IParser parser;
if (!this._Parsers.TryGetValue(targetType, out parser))
{
// no parser was found, so check the target type for a Parser attribute
object[] attributes = targetType.GetCustomAttributes(typeof(ParserAttribute), true);
if (attributes != null && attributes.Length > 0)
{
ParserAttribute parserAttribute = (ParserAttribute)attributes[0];
// create an instance of the identified parser
parser = (IParser<T>)Activator.CreateInstance(parserAttribute.ParserType);
// and add it to the dictionary
this._Parsers.Add(targetType, parser);
}
else
{
throw new InvalidOperationException(string.Format("Unable to find a parser for the type [{0}].", targetType.Name));
}
}
return (IParser<T>)parser;
}
// this method can be used to set up parsers without the use of the Parser attribute
public void RegisterParser<T>(IParser<T> parser)
{
this._Parsers[typeof(T)] = parser;
}
}
使用示例:
ParserRepository parserRepository = new ParserRepository();
// ...
IParser<MyObjectA> parserForMyObjectA = parserRepository.GetParser<MyObjectA>();
IParser<MyObjectB> parserForMyObjectB = parserRepository.GetParser<MyObjectB>();
using (var fs = new FileStream(@"file.ext", FileMode.Open, FileAccess.Read, FileShare.Read))
{
BinaryReader br = new BinaryReader(fs);
MyObjectA objA = parserForMyObjectA.Read(br);
MyObjectB objB = parserForMyObjectB.Read(br);
// ...
}
// Notice that this code does not explicitly reference the MyObjectAParser or MyObjectBParser classes.