我似乎记得在某处读到C#中虚拟调用的成本并不像在C++中那么高.这是真的?如果是这样 - 为什么?
在Visual Studio 2008中,编译器无法解析调用SetCustomer在_tmain下面,并使其明确:
template <typename TConsumer>
struct Producer
{
void SetConsumer(TConsumer* consumer) { consumer_ = consumer; }
TConsumer* consumer_;
};
struct AppleConsumer
{
};
struct MeatConsumer
{
};
struct ShillyShallyProducer : public Producer<AppleConsumer>,
public Producer<MeatConsumer>
{
};
int _tmain(int argc, _TCHAR* argv[])
{
ShillyShallyProducer producer;
AppleConsumer consumer;
producer.SetConsumer(&consumer); // <--- Ambiguous call!!
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是编译错误:
// error C2385: ambiguous access of 'SetConsumer'
// could be the 'SetConsumer' in base 'Producer<AppleConsumer>'
// or could be the …Run Code Online (Sandbox Code Playgroud) 特定
IEnumerable<T> first;
IEnumerable<T> second;
Run Code Online (Sandbox Code Playgroud)
并且,这两个first和second由一个比较器进行排序Func<T, T, int>,对于平等返回0,-1时,第一被"较小"和1时第二个是"较小".
是否有一种直接的方法使用LINQ合并两个序列,使得结果序列也由同一个比较器排序?
我们目前正在使用手工制作的算法,但是直接LINQ语句的可读性会更好.
我们有这个代码,排序:
private void InitializeEvents()
{
this.Event1 += (s,e) => { };
this.Event2 += (s,e) => { };
this.Event3 += (s,e) => { };
this.Event4 += (s,e) => { };
this.Event5 += (s,e) => { };
this.Event6 += (s,e) => { };
this.Event7 += (s,e) => { };
this.Event8 += (s,e) => { };
this.Event9 += (s,e) => { };
this.Event10 += (s,e) => { };
this.Event11 += (s,e) => { };
this.Event12 += (s,e) => { };
this.Event13 += (s,e) …Run Code Online (Sandbox Code Playgroud) 我很想听听您在操作过程中使用什么技术来验证对象的内部状态,从它自己的角度来看,只能因为内部状态不良或不变违规而失败.
我主要关注的是C++,因为在C#中官方和流行的方式是抛出一个异常,并在C++中有不只是一个单一的方式做到这一点(OK,不是真的在C#或者,我知道).
请注意,我不是在讨论函数参数验证,而是更像是类不变完整性检查.
例如,假设我们想要一个异步打印作业的Printer对象Queue.对于用户来说Printer,该操作只能成功,因为异步队列的结果会在另一时间到达.因此,没有相关的错误代码传达给调用者.
但是对于该Printer对象,如果内部状态不好,则该操作可能会失败,即类不变被破坏,这基本上意味着:一个错误.该条件不一定是Printer对象的用户感兴趣的.
就个人而言,我倾向于混合三种内部状态验证方式,我无法确定哪一个是最好的,如果有的话,哪一个绝对是最差的.我想听听你对这些问题的看法,以及你在这个问题上分享你自己的经验和想法.
我使用的第一种风格 - 以可控制的方式比损坏的数据更好地失败:
void Printer::Queue(const PrintJob& job)
{
// Validate the state in both release and debug builds.
// Never proceed with the queuing in a bad state.
if(!IsValidState())
{
throw InvalidOperationException();
}
// Continue with queuing, parameter checking, etc.
// Internal state is guaranteed to be good.
}
Run Code Online (Sandbox Code Playgroud)
我使用的第二种风格 - 比腐败数据更难以控制崩溃:
void Printer::Queue(const PrintJob& job)
{
// Validate the …Run Code Online (Sandbox Code Playgroud) 我经常读到,从一个perf的角度看,在汇编指令级别的分支是不好的.但我还没有真正理解为什么会这样.所以为什么?
为只能通过值传递的句柄编写包装类相对容易.我试图确定封装需要通过地址传递的句柄的最佳方法是什么.
例如,编写一个类似SC_HANDLE的包装器,它通过值传递给QueryServiceConfig()并不困难.一个可以实现像一个成员函数.GetHandle()或实现运算符() .
问题(至少对我来说)是像RegOpenKeyEx()这样的API函数,它需要HKEY的地址.
我读过重载运算符&通常是一个坏主意.在允许API函数访问的同时,保持封装(或尽可能多的封装)以及特别是资源集合的推荐方法是什么?
这"总是"困扰着我......
假设我有一个接口IFiddle和另一个接口,除了聚合几个不同的IFiddles 之外什么都不做:
public interface IFiddleFrobbler
{
IFiddle Superior { get; }
IFiddle Better { get; }
IFiddle Ordinary { get; }
IFiddle Worse { get; }
IFiddle Crackpot { get; }
}
Run Code Online (Sandbox Code Playgroud)
(具体的IFiddleFrobblers和IFiddles取决于配置,由工厂创建.)
我一再偶然发现这种"伞"类型的命名 - 我想用描述性的东西来交换"Frobbler".
请赐教,我的"伞"类型的命名方案是什么?
编辑:正如xtofl在评论中指出的那样,实际上比我上面首次公开的语义更多.如果我改为做以下事情,我认为我的需要更清楚:
//
// Used for places where the font width might need
// to be tapered for a rendered text to fit.
//
public …Run Code Online (Sandbox Code Playgroud) 在C++中,我经常需要NVI才能在API中获得一致性.不过,在C#中我没有看到它用得那么多.我想知道这是因为C#作为一种语言,提供的功能使得NVI不再需要吗?(尽管如此,我仍然在C#中使用NVI.)
在以前需要高耐用性和长期向上的时间,我一直是大规模应用的验证指针函数的参数,当它被记录为"绝不能为空".std::invalid_argument如果参数在C++中实际为NULL并且在C中返回错误代码,那么我会抛出异常或类似的异常.
但是,我开始认为也许最好让应用程序立即在同一个函数中的第一个NULL指针取消引用中爆炸 - 然后崩溃转储文件将揭示发生了什么 - 并让一个彻底的测试过程发现坏的函数调用.
不检查NULL并让应用程序爆炸的一个问题是,如果指针实际上没有在该函数中解除引用,而是存储以供以后使用,那么解除引用爆炸将脱离上下文并且更难以诊断.
有关于此的任何想法或最佳做法?
编辑1:我忘了提到我们的许多代码都是第三方开发人员的库,可能会或可能不知道我们的内部错误处理策略.但功能仍然正确记录!
c# ×6
c++ ×6
validation ×2
assembly ×1
c ×1
code-metrics ×1
cpu ×1
fxcop ×1
idioms ×1
invariants ×1
linq ×1
naming ×1
oop ×1
polymorphism ×1
raii ×1
system ×1
templates ×1
virtual ×1
winapi ×1
windows ×1