我已经创建了一个运行PowerShell脚本的函数,并且需要一种具有不同返回值类型的方法。在我的情况下是Collection<PSObject>
或Collection<ErrorRecord>
。
我尝试使用元组,尝试使用Dynamic ...有更好的方法吗?
这是我使用最新方法的代码:动态。
public static dynamic PowerShellLocal(string scriptBlock)
{
using (PowerShell powerShell = PowerShell.Create())
{
object endResult = null;
powerShell.AddScript(scriptBlock);
var results = powerShell.Invoke();
if (powerShell.Streams.Error.Count > 0)
{
endResult = error;
}
else
{
endResult = result;
}
return endResult;
}
}
这种方法给了我一个例外,给了我一个我无法枚举的例外,因为然后在我的代码中,我使用每个例外来遍历结果。 有更好的方法吗?
答案 0 :(得分:3)
要返回多种类型时,一种选择是将它们包装在具有要返回的类型属性的类中。
例如:
class PowerShellResult
{
public List<ErrorRecord> ErrorRecords { get; set; }
public List<PSObject> Results { get; set; }
}
然后,您可以返回这种新类型的对象:
public static PowerShellResult PowerShellLocal(string scriptBlock)
{
var result = new PowerShellResult();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(scriptBlock);
result.Results = powerShell.Invoke().ToList();
result.ErrorRecords = powerShell.Streams.Error.ToList();
}
return result;
}
另一个常见的选择是直接从方法中返回一种类型,并对另一种类型使用out
参数。
例如:
public static IEnumerable<PSObject> PowerShellLocal(string scriptBlock,
out IEnumerable<ErrorRecord> errors)
{
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(scriptBlock);
var results = powerShell.Invoke();
errors = powerShell.Streams.Error.ToList();
return results.ToList();
}
}
答案 1 :(得分:0)
使用wp_130638636
/ try
方法,该函数返回您的catch
,如果脚本有错误,请收集Collection<PSObject>
,并抛出{ {3}},如果您可以轻松地将ErrorRecords
转换为ErrorRecord
,或者编写自己的自定义Exception
类。 (除非Exception
是ErrorRecord
的子类,否则后者肯定会更好,根据C#的命名约定,它不是。)
Exception
前言:我 不 推荐这种方法,但是它确实回答了最简单的问题。
您可以返回public class PSScriptException : Exception
{
public PSScriptException(Collection<ErrorRecord> errorRecords)
{
this.ErrorRecords = errorRecords;
}
public PSScriptException(Collection<ErrorRecord> errorRecords, string message): this(errorRecords)
{
this.Message = message;
}
Collection<ErrorRecord> ErrorRecords { public get; private set; }
}
// ...
// within some class
public static Collection<PSObject> PowerShellLocal(string scriptBlock)
{
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(scriptBlock);
var results = powerShell.Invoke();
if (powerShell.Streams.Error.Count > 0)
{
throw new PSScriptException(powerShell.Streams.Error.ToList());
}
return results.ToList();
}
}
// ...
void DoScript(string scriptBlock)
{
try
{
Collection<PSObject> results = PowerShellLocal(scriptBlock);
doTheThing(results);
}
catch (PSScriptException scriptEx)
{
handleTheErrors(scriptEx);
}
}
,然后在使用结果的任何地方检查其类型。
Collection<object>
我不建议这样做的原因是C#故意是一种强类型的语言。如果您不想使用Collection<object> myResult = PowerShellLocal(myScript);
if (myResult is Collection<PSObject> myPSObjects) {
doTheThing(myPSObjects);
}
else
{
Collection<ErrorRecord> myErrors = myResult as Collection<ErrorRecord>;
handleTheError(myErrors);
}
/ try
方法,则在@Rafus的答案中使用catch
参数可以提供比此答案更好的方法。
答案 2 :(得分:0)
using "object" cuold be a good solution?
public static object PowerShellLocal(string scriptBlock)
答案 3 :(得分:0)
您要的是功能API合同,而没有提供有关如何使用此功能的上下文。
函数的使用者将如何处理结果?
对于问题“如何从一个函数返回两种不同类型的问题”,您已经有了很好的答案。但是实际的问题是,这些方法将为功能的使用者产生多少“麻烦”。
作为功能的消费者
-我需要为每个通话提供一个变量
-如果我关心错误,则每次调用方法时,都需要检查是否存在错误
-如果我不在乎可能的错误,则创建out
错误变量是没有用的
基于逻辑功能将仅返回一个结果,该结果可以是“成功”类型或“错误”类型。
这就是为什么问题“您将如何使用此方法?”非常重要(您未正确回答)。
只是出于娱乐目的,例如,我想您要在结果成功时将结果保存到数据库中,而在功能失败时将其保存到“错误”中。
然后,我将创建一个接口来抽象结果的行为。
public interface ISavePowerShellResult
{
void Save();
}
然后将创建此接口的实现,一个用于Sql数据库(成功的记录),另一个用于XML文件(错误)。
public class SaveSuccessfulObjects : ISavePowerShellResult
{
private IEnumerable<PSObject> _objects;
public SaveSuccessfulObjects(IEnumerable<PSObject> objects) => _objects = objects;
public void Save()
{
foreach (var psobject in _objects)
{
// save to sql database
}
}
}
public class SaveErrors : ISavePowerShellResult
{
private IEnumerable<ErrorRecord> _errors;
public SaveErrors(IEnumerable<ErrorRecord> errors) => _errors = errors;
public void Save()
{
foreach (var record in _errors)
{
// save error to xml file
}
}
}
使返回的类型成为接口并返回该接口的实现的函数。
public static ISavePowerShellResult PowerShellLocal(string scriptBlock)
{
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(scriptBlock);
var results = powerShell.Invoke();
if (powerShell.Streams.Error.Count > 0)
{
return new SaveErrors(powerShell.Streams.Error);
}
return new SaveSuccessfulObjects(results);
}
}
然后,该功能的使用对于消费者而言将非常简单。
var script = "Invoke-Something ...";
var result = PowerShellLocal(script);
result.Save();
使用这种方法,可以为函数添加更多功能变得容易得多,因为只需要做的就是创建接口的新实现,而无需触及使用函数的代码。