如何在C#中对函数具有不同的返回值

时间:2019-01-09 18:06:58

标签: c#

我已经创建了一个运行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;
            }
        }

这种方法给了我一个例外,给了我一个我无法枚举的例外,因为然后在我的代码中,我使用每个例外来遍历结果。 有更好的方法吗?

4 个答案:

答案 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类。 (除非ExceptionErrorRecord的子类,否则后者肯定会更好,根据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();

使用这种方法,可以为函数添加更多功能变得容易得多,因为只需要做的就是创建接口的新实现,而无需触及使用函数的代码。