高效优雅的代码(翻译)

高效优雅的代码

我仍然很忙,主要是在Revit API讨论论坛中这里有两个最近的样本处理非常通用的效率相关问题:

 

 

优雅和高效

 

 

简单代码中的效率与优雅

在最近的一项课题的Revit API论坛询问与简单的代码效率和优雅的帮助

问题:我的代码有效,但我认为它没有那么高效。具体来说,代码的Try / catch区域。如果我不单独尝试/捕捉每条线,它会错过一些门。如果可能的话,也喜欢减少再生时间。任何指针都表示赞赏。谢谢。

 
 1  // Get doors
 2   FilteredElementCollector collector = new FilteredElementCollector( doc );
 3   List<Element> coll = collector.OfClass( typeof( FamilyInstance ) )
 4     .OfCategory( BuiltInCategory.OST_Doors )
 5     .ToList();
 6 
 7   // Filtered element collector is iterable
 8   foreach( Element e in coll )
 9   {
10     // Get the parameter name
11     Parameter s_parameter = e.LookupParameter( "Swing Angle" );
12     Parameter s1_parameter = e.LookupParameter( "Swing Angle_Door 1" );
13     Parameter s2_parameter = e.LookupParameter( "Swing Angle_Door 2" );
14     using( Transaction t = new Transaction( doc, "parameters" ) )
15 
16     // Modify document within a transaction
17     using( Transaction tx = new Transaction( doc ) )
18     {
19       tx.Start( "Change door swing angles to 45" );
20 
21       try
22       {
23         s_parameter.Set( 0.785398163 );
24       }
25       catch { }
26       try
27       {
28         s1_parameter.Set( 0.785398163 );
29       }
30       catch { }
31       try
32       {
33         s2_parameter.Set( 0.785398163 );
34       }
35       catch { }
36       tx.Commit();
37     }
38   }
39   TaskDialog.Show( "Completed", "Door swings changed to 45°." );
40   return Result.Succeeded;

 

通过回答MarryTookMyCoffe:

  • 更改ListArray你不必改变foreachfor,因为编译器通常会为你,但请记住,没有的代码优化,for比速度更快foreach
  • 删除第一个
 1 using (Transaction t = new Transaction(doc, "parameters")) 
  • 为什么会这样呢?你把using交易放在using交易中; 为什么?
  • 将循环放在事务中,而不是在外部(每次启动和提交都需要花费很多时间)。
  • 如果使用string属性获取参数,则必须检查参数是否为null:
 1 if(s_parameter != null) 
  • 检查参数是否为只读,以及是否为double值。
  • 因此,应用程序只能返回Succeeded
  • 你在改变类型或实例吗?您可以添加WhereElementIsElementType到已过滤的元素收集器。

试试这个:

 1  [Transaction( TransactionMode.Manual )]
 2   public class Command : IExternalCommand
 3   {
 4     private const double angle = 0.785398163;
 5     public Result Execute(
 6       ExternalCommandData commandData,
 7       ref string message,
 8       ElementSet elements )
 9     {
10       Document doc = commandData.Application.ActiveUIDocument.Document;
11       // Get instance of doors
12       Element[] coll = new FilteredElementCollector( doc )
13         .OfClass( typeof( FamilyInstance ) )
14         .OfCategory( BuiltInCategory.OST_Doors )
15         .WhereElementIsNotElementType()
16         .ToArray();
17 
18       // Start transaction outside of loop, that way you only open transaction once
19       using( Transaction tx = new Transaction( doc ) )
20       {
21         tx.Start( "Change door swing angles to 45" );
22         foreach( Element e in coll )
23         {
24           //set Parameter by the name
25           try
26           {
27             SetParameter( e, "Swing Angle", angle );
28             SetParameter( e, "Swing Angle_Door 1", angle );
29             SetParameter( e, "Swing Angle_Door 2", angle );
30           }
31           catch { }
32         }
33         tx.Commit();
34       }
35       TaskDialog.Show( "Completed", "Door swings changed to 45°." );
36       return Result.Succeeded;
37     }
38 
39     /// <summary>
40     /// set double parameter by value
41     /// </summary>
42     /// <param name="element"></param>
43     /// <param name="Name"></param>
44     /// <param name="value"></param>
45     /// <returns></returns>
46     private static bool SetParameter( Element element, string Name, double value )
47     {
48       Parameter parameter = element.LookupParameter( Name );
49       // Preventing exceptions is better than catching it 
50       if( parameter != null && !parameter.IsReadOnly && parameter.StorageType == StorageType.Double )
51         return parameter.Set( value );
52       return false;
53     }
54   }

 

回复:谢谢,完美的工作。现在我将逐步完成代码,以便了解您的所作所为。再次感谢!

答案2:我想补充几点:

LookupParameter只会检索给定名称的第一个参数。为了使用它,您必须绝对确定只存在具有给定名称的一个参数。我建议在加载项启动代码中的某处添加一个测试,以确保实际情况如此。

使用其他方法检索参数总是更安全,例如,内置参数枚举值(如果存在),或者只是Parameter定义,您可以预先查找并缓存,例如,在上述代码中确保该元素类型的参数名称确实是唯一的。

没有必要将元素集合转换为数组,即说

  1 Element[] coll = new FilteredElementCollector( doc )...ToArray(); 

你完全可以把它作为一个过滤后的元素收集器,并直接迭代它:

 
1 FilteredElementCollector coll = new FilteredElementCollector( doc )...;
2   foreach( Element e in coll ) ...

 

这将节省转换时间和空间,避免不必要的数据重复,参见 讨论:

将墙壁类型推到门上

关于将墙式推入门的问题中出现了一些非常相似的代码

问题:我已经在这个宏上工作了一段时间,我们正在寻找一种方法来让我们的门时间表包含墙类型(可在Type Mark参数中找到)。我附在我所在的地方。将墙上的实例参数拉到门中的实例参数我没有任何问题,但我对墙上的类型参数没有太大的帮助。我不确定的唯一区域是我是否正确访问了墙上的类型参数:

 1  public void WalltoDoor2()
 2   {
 3     Document doc = this.ActiveUIDocument.Document;
 4 
 5     ElementCategoryFilter hostFilter 
 6       = new ElementCategoryFilter( 
 7         BuiltInCategory.OST_Walls );
 8     ElementCategoryFilter hostedFilter 
 9       = new ElementCategoryFilter(
10         BuiltInCategory.OST_Doors );
11 
12     string parameterName = "Type Mark";
13     string parameterName2 = "Wall Type";
14     using( Transaction t = new Transaction( 
15       doc, "Set hosted parameters" ) )
16     {
17       try
18       {
19         t.Start();
20         foreach( Element host in 
21           new FilteredElementCollector( doc )
22             .WherePasses( hostFilter ) )
23         {
24           if( host != null )
25           {
26             Element hostT = host.Document.GetElement( 
27               host.GetTypeId() );
28             Parameter paramHost = hostT.LookupParameter( 
29               parameterName );
30 
31             foreach( Element hosted in 
32               new FilteredElementCollector( doc )
33                 .WherePasses( hostedFilter )
34                 .OfClass( typeof( FamilyInstance ) )
35                 .Cast<FamilyInstance>()
36                 .Where( q => q.Host.Id == host.Id ) )
37             {
38               if( hosted != null )
39               {
40                 hosted.LookupParameter( parameterName2 )
41                   .Set( paramHost.AsString() );
42               }
43             }
44           }
45         }
46         t.Commit();
47       }
48       catch( Exception )
49       {
50       }
51     }
52   }

 

答案:使用内置参数检查器,类型标记看起来像是墙的“ALL_MODEL_TYPE_MARK”。

尝试使用:

  1 hostT.LookupParameter("ALL_MODEL_TYPE_MARK"); 

以下是清理代码的另外两个建议:

posted @ 2019-01-08 11:06  AnnLT  阅读(189)  评论(0)    收藏  举报