【问题标题】:Generic property disadvantages?通用属性的缺点?
【发布时间】:2011-05-07 07:26:19
【问题描述】:

我在我的项目中使用通用属性,但我不知道,使用它们有什么缺点,请告诉我一个场景,它们有缺点吗?下面是我的部分代码。

public class GenericResult<T>
{
    public T Data { get; set; }
    public bool IsSuccess { get; set; }
    public string Message { get; set; }
}

public GenericResult<int> AddCategory(TCategory tCategory)
{
    GenericResult<int> result = new GenericResult<int>();

    //business logic validation,dont make sense,only example :)
    if (tCategory.Name.Lenght > 100)
    {
        result.IsSuccess = false;
        result.Message = "Category Name length is too long";
        result.Data = 0;
    }

    //handle .net runtime error//may be database is not aviable.
    try
    {
        result.Data = this.catalogRepository.AddCategory(tCategory);
        result.IsSuccess = true;
    }
    catch (Exception ex)
    {
        result.Data = 0;
        result.IsSuccess = false;
        result.Message = ex.Message;
    }
    return result;
}

public GenericResult<IEnumerable<TCategory>> GetCategoryHierarchy(TCategory parentCategory)
{
    GenericResult<IEnumerable<TCategory>> result = new GenericResult<IEnumerable<TCategory>>();
    try
    {
        IEnumerable<TCategory> allCategories = catalogRepository.GetAllCategories();
        result.Data = GetCategoryHierarchy(allCategories, parentCategory);
        result.IsSuccess = true;

    }
    catch (Exception ex)
    {
        result.IsSuccess = false;
        result.Data = null;
        result.Message = ex.Message;
    }
    return result;
} 

【问题讨论】:

  • 如果 AddCategory 失败,为什么要返回一个实例?这通常被认为是不好的做法。返回 null 以使外部可以清楚地看到失败。
  • 同意马里奥的观点,但抛出异常可能更具表现力,以便向所有人展示出了问题!!!
  • null 不会给您任何消息。他返回的是 MayBe&lt;T&gt; 的自制版本,这在其他语言中是一个很好的模式。

标签: c# .net generics


【解决方案1】:

如果您不想抛出异常,但希望返回包含错误或值的结果,即 MayBe,在某些情况下这很好。但老实说,在这种情况下,我更喜欢简单地抛出/传递异常。

我更喜欢将不可变结构返回为MayBe,而不是像您那样返回可变类。它与Nullable&lt;T&gt; 非常相似,除了它适用于引用类型并且可以存储错误。比如:

public struct MayBe<T>
{
    private T value;
    private Exception error;

    public bool HasValue{get{return error==null;}}
    public T Value
    {
      if(error!=null)
        throw error;
      else
        return value;
    }

    public static MayBe<T> CreateError(Exception exception)
    {
      return new MayBe<T>(default(T),exception);
    }

    public static MayBe<T> CreateValue(T value)
    {
      return new MayBe<T>(value,null);
    }

    public static implicit operator MayBe<T>(T value)
    {
        return CreateValue(value);
    }

    public override string ToString()
    {
        if(HasValue)
            return "Value: "+Value.ToString();
        else
            return "Error: "+Error.GetType().Name+" "+Error.Message;
    }
}

你的代码变成了

public MayBe<int> AddCategory(TCategory tCategory)
{
    try
    {
       return this.catalogRepository.AddCategory(tCategory);
    }
    catch (Exception ex)
    {
        return MayBe<int>.CreateError(ex);
    }

    return result;
}

public MayBe<IEnumerable<TCategory>> GetCategoryHierarchy(TCategory parentCategory)
{
    try
    {
        IEnumerable<TCategory> allCategories = catalogRepository.GetAllCategories();
        return allCategories;

    }
    catch (Exception ex)
    {
        return MayBe<int>.CreateError(ex);
    }

    return result;
}

我看到这个实现的一个问题是异常不是完全不可变的。如果相同的MayBe&lt;T&gt; 在多个线程上抛出,这可能会导致问题。也许有人可以提出更好的实施方案。

【讨论】:

  • 因为 1) 不能是null。因为我们已经在内部处理了null 值,所以将整个MayBe 变成null 没有多大意义2)它很便宜。它只有两个字段。 3) 由于它是不可变的,因此除了可空性之外几乎没有语义差异。
【解决方案2】:

我宁愿删除 IsSuccessMessage 并只返回对象。见下文...

看看我的问题Good practices when handling Exceptions in C#。您返回的是错误,而不是抛出异常,在.NET 中,不建议这样做。

From MSDN

不返回错误代码。异常是在框架中报告错误的主要方式。


在我读过的一些文章/书籍中建议了你正在做的事情,包括The Pragmatic Programmer: From Journeyman to Masterthis Joel Spolsky article,但正如 MSDN 所说,在 .NET 中,例外情况更适合此目的.

编辑:
如果您仍然想这样做(即使这可能给使用您的代码的开发人员带来一些问题),我认为总的来说,这可能是一个好方法。实际上,我将编辑我在此答案上链接的问题,以放置指向您的代码的链接,以替代返回 errors 而不是在 .NET 中引发异常

【讨论】:

  • 但我不想只处理异常,我想简化我的验证处理,我已经编辑了我的问题,如下所示 if(tCategory.Name == null) { result.IsSuccess = false; result.Message = "类别名称不能为空";结果.数据 = 0; }
  • @tobias 那和做有什么区别:throw new ArgumentNullException("Category Name cannot be null"); 或只是throw new ArgumentNullException("tCategory");?我的意思是,你仍然可以验证并让调用者知道错误是什么......
  • 并非总是如此,假设您正在构建一个 UI 框架或一组在 UI 中工作的东西,如果您只是抛出异常,默认 UI 框架可能无法执行其自己的待处理任务。当你不想用你的异常来干扰底层框架并以不同的方式执行你的任务时,这种模式还有什么用处。
  • @AkashKava 没错。事实上,我赞成你的回答,因为我同意你解释的场景(JSON、webservices、..),但我的意思是它不会让验证更容易,不是吗?
  • @Oscar,是的,我觉得关于验证的重点仍然取决于具体情况。这取决于谁捕获和处理验证。我想 MSDN 上所说的一切都是为了让人们意识到并将他们的编程风格从“函数式 C”更改为“面向对象的 C#”,异常是最好的,但应该明智地选择如何合并它们。
【解决方案3】:

如果您的应用程序范围完全在 .NET 范围内,那么这种模式是没有用的,正如其他人所提到的,您应该允许抛出异常并且您可能想要更改异常。

但是,如果您的应用程序范围很广,可能包括任何其他客户端框架,可能通过 JSON、Web 服务等,并且如果客户端框架不能正确支持异常,那么这种模式可能会很有用。例如,在基于 JSON 的 Javascript 调用中,您将始终期待一个结果,以及一条指示服务器端是否失败的消息。客户端故障可能是服务器端故障或网络故障,通常所有客户端框架都会检测并仅报告网络故障,并且当您在客户端不会收到任何错误报告时,错误编码的框架将导致混乱服务器端。

此模式还有一个非常有用的地方是,当您在 UI 或其他人的框架中编写一些插件时,只要抛出异常就会导致不希望的结果,因为在出​​现异常后,第三方框架可能会说“意外错误”因为他们没有,他们也不会理解你的例外。这种模式在处于其他人的框架内并且无论您失败如何仍然让底层框架正常工作时很有用。而且您可能可以在您的应用框架内正确通信。

我最近看到,它仍然是一个错误,如果您将图像源设置为 Web 地址且不存在,WPF 将停止处理一些未决的 UI 相关活动。您将看到跟踪的网络相关异常,但 WPF 将不完全停止处理待处理任务中的任何内容,并且应用程序仍然可以工作,但它确实会影响不应影响的其他 UI 元素。

【讨论】:

  • 类似的模式在函数式编程中非常有用。
【解决方案4】:

自动属性的使用很好,我没有发现任何问题。

但我强烈反对使用类来告诉外界某事失败的模式。严重失败时返回 null 或抛出异常。

马里奥

【讨论】:

  • 返回null 会清除错误信息,在某些情况下抛出异常可能会很慢或很烦人。尤其是在函数式编程中。
猜你喜欢
  • 2021-03-06
  • 2017-12-14
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多