-1

所以我有一个 WPF 应用程序,它有一个带有子 MVVM 的基本 MVVM。我尝试用谷歌搜索答案,但不确定技术术语,所以我将在下面提供两个示例,也许有人可以让我对示例的效率有所了解。我想知道开销是否有很小的差异或显着。

假设我有一个类似于以下的设置

public class ParentViewModel
{
    public ParentViewModel()
    {
        Child = new ChildViewModel();
    }

    public ChildViewModel Child { get; set; }
}

public class ChildViewModel
{
    public ChildViewModel()
    {
        GrandChild = new GrandChildViewModel();
    }

    public GrandChildViewModel GrandChild { get; set; }
}

public class GrandChildViewModel
{
    public GrandChildViewModel()
    {
        GreatGrandChild = new GreatGrandChildViewModel();
    }

    public GreatGrandChildViewModel GreatGrandChild { get; set; }
}

public class GreatGrandChildViewModel
{
    public GreatGrandChildViewModel()
    {
         intA = 1;
         intB = 2;
         intC = 3;
    }

    public int intA { get; set; }
    public int intB { get; set; }
    public int intC { get; set; }
}

以下两个使用示例是我想要了解的地方。

示例 1:

public Main()
{
     var parent = new ParentViewModel();

     Console.WriteLine($"A: {parent.Child.GrandChild.GreatGrandChild.intA}" +
                       $"B: {parent.Child.GrandChild.GreatGrandChild.intB}" +
                       $"C: {parent.Child.GrandChild.GreatGrandChild.intC}");
}

示例 2:

public Main()
{
     var greatGrandChild = new ParentViewModel().Child.GrandChild.GreatGrandChild;

     Console.WriteLine($"A: {greatGrandChild.intA}" +
                       $"B: {greatGrandChild.intB}" +
                       $"C: {greatGrandChild.intC}");
}

哪个效率更高?我之所以问,是因为我认为示例 2 会更有效,因为它会下降到最低级别一次,然后访问 intA、intB 和 intC。这有关系吗?性能差异是否显着?

4

3 回答 3

1

您会注意到两者之间绝对没有优化。事实上,我怀疑编译器会将这两种类型的语句优化为同一个 IL。

但是,后一个示例更具可读性,因此我会选择这种方法。

于 2017-03-31T21:11:28.473 回答
1

我建议您购买所需的最小对象。

在您给出的示例中,性能差异可以忽略不计,但如果父/祖父母/曾祖父对象中恰好有更多数据,并且如果您正在传递这个对象(尤其是通过网络),那么它可能会使一个区别。想象一下,将某人的整个家谱对象传递给某个真正只需要此人姓名的 Web 服务。

但它也通过抓取您需要的最小物体来显示您的意图。故意编程通常更易于阅读和维护,并且可以让您更轻松地发现错误。

于 2017-03-31T23:27:27.830 回答
1

虽然最初的想法是编译器会针对相同的 IL 进行优化,但这显然不是真的

虽然我没有检查过 IL,但快速而肮脏的秒表测试表明,孙子路线要快得多

使用问题中的视图模型,结果如下:

var parent = new ParentViewModel();
var greatGrandChild = new ParentViewModel().Child.GrandChild.GreatGrandChild;
var watch = new Stopwatch();

var a = parent.Child.GrandChild.GreatGrandChild.intA;
var b = parent.Child.GrandChild.GreatGrandChild.intB;
var c = parent.Child.GrandChild.GreatGrandChild.intC;

var bothTotal = 0L;
var longTotal = 0L;
var shortTotal = 0L;

watch.Start();
a = parent.Child.GrandChild.GreatGrandChild.intA;
b = parent.Child.GrandChild.GreatGrandChild.intB;
c = parent.Child.GrandChild.GreatGrandChild.intC;
a = greatGrandChild.intA;
b = greatGrandChild.intB;
c = greatGrandChild.intC;
watch.Stop();
bothTotal += watch.ElapsedTicks;
watch.Reset();          
Console.WriteLine("Longhand and Shorthand: " + bothTotal);

watch.Start();
a = parent.Child.GrandChild.GreatGrandChild.intA;
b = parent.Child.GrandChild.GreatGrandChild.intB;
c = parent.Child.GrandChild.GreatGrandChild.intC;
a = parent.Child.GrandChild.GreatGrandChild.intA;
b = parent.Child.GrandChild.GreatGrandChild.intB;
c = parent.Child.GrandChild.GreatGrandChild.intC;
watch.Stop();
longTotal += watch.ElapsedTicks;
watch.Reset();          
Console.WriteLine("Longhand Only: " + longTotal);

watch.Start();
a = greatGrandChild.intA;
b = greatGrandChild.intB;
c = greatGrandChild.intC;
a = greatGrandChild.intA;
b = greatGrandChild.intB;
c = greatGrandChild.intC;
watch.Stop();
shortTotal += watch.ElapsedTicks;
watch.Reset();          
Console.WriteLine("Shorthand Only: " + shortTotal);

这些是我的典型结果:

Longhand and Shorthand: 22
Longhand Only: 3
Shorthand Only: 2

这显然不是最细粒度的测试,而且肯定有一些事情可以说是倾向于确认偏差 - 但从表面上看,“速记”路线似乎更佳,值得进一步测试

更新

我检查了生成的 IL,结果非常清楚:

速记:

// Setup the object:
newobj     instance void ParentViewModel::.ctor()

// Actually call the members:
callvirt   instance class ChildViewModel ParentViewModel::get_Child()
callvirt   instance class GrandChildViewModel ChildViewModel::get_GrandChild()
callvirt   instance class GreatGrandChildViewModel 
GrandChildViewModel::get_GreatGrandChild()
callvirt   instance int32 GreatGrandChildViewModel::get_intA()
callvirt   instance class ChildViewModel ParentViewModel::get_Child()
callvirt   instance class GrandChildViewModel ChildViewModel::get_GrandChild()
callvirt   instance class GreatGrandChildViewModel 
GrandChildViewModel::get_GreatGrandChild()
callvirt   instance int32 GreatGrandChildViewModel::get_intB()
callvirt   instance class ChildViewModel ParentViewModel::get_Child()
callvirt   instance class GrandChildViewModel ChildViewModel::get_GrandChild()
callvirt   instance class GreatGrandChildViewModel 
GrandChildViewModel::get_GreatGrandChild()
callvirt   instance int32 GreatGrandChildViewModel::get_intC()

速记:

// Setup the object
newobj     instance void ParentViewModel::.ctor()
call       instance class ChildViewModel ParentViewModel::get_Child()
callvirt   instance class GrandChildViewModel ChildViewModel::get_GrandChild()
callvirt   instance class GreatGrandChildViewModel GrandChildViewModel::get_GreatGrandChild()

// Actually call the members:
callvirt   instance int32 GreatGrandChildViewModel::get_intA()
callvirt   instance int32 GreatGrandChildViewModel::get_intB()
callvirt   instance int32 GreatGrandChildViewModel::get_intC()
于 2017-03-31T23:57:16.330 回答