在不使用扩展方法的情况下,用通用逻辑扩展c#接口
本文关键字:扩展 接口 方法 情况下 | 更新日期: 2023-09-27 18:08:07
是否有不使用扩展方法扩展接口的方法?
如果我用几个get/set字符串定义一些接口,例如:
public interface IMyItem
{
string Title { get; set; }
string Description { get; set; }
}
我想为这些接口添加一些简单的验证,但是没有重新定义逻辑或强制某种形式的继承。
目前我正在使用扩展方法,像这样:
public static class MyItemExtensions
{
public static bool ERROR(this IMyItem item)
{
return item.TITLE_ERROR() || item.DESCRIPTION_ERROR();
}
public static bool TITLE_ERROR(this IMyItem item)
{
return string.IsNullOrEmpty(item.Title);
}
public static bool DESCRIPTION_ERROR(this IMyItem item)
{
return string.IsNullOrEmpty(item.Description);
}
}
这样做有效,我可以有:
public class Item : IMyItem
{
public string Title { get; set; }
public string Description { get; set; }
}
public static class app
{
public static void go()
{
var item = new Item
{
Title = "My Item Title",
Description = ""
};
Console.log(item.ERROR());
}
}
但我更喜欢ERROR
, TITLE_ERROR
&DESCRIPTION_ERROR
是否有一种方法可以达到同样的效果,但要暴露获取/设置属性而不是扩展方法?
更新11/06/2014
正如许多人建议的那样,基于该示例,abstract
类将是一个明显的解决方案,但是类型需要实现多个接口。虽然可以安排继承,但这会给类型带来不必要的复杂性和限制。
在这些接口上使用扩展方法进行验证的额外好处是允许上下文特定的&通过名称空间使用共享逻辑。
可以在不同的命名空间上为接口定义多个ERROR(this IMyItem item)
扩展方法。一个同时检查TITLE_ERROR
和DESCRIPTION_ERROR
,另一个可能只测试其中一个属性。然后,根据上下文,可以引用相关的名称空间,并执行该项的共享验证。
我将看看微软的验证器,但它看起来相当冗长,我真的希望这些状态作为类型的属性,因为它使使用它们的代码更容易使用。
此外,这些都是非常简单的例子,有些验证要复杂得多,有些情况下需要与其他web服务进行交互——尽管是针对AppDomain内的web服务数据缓存。
目前这些
interface
扩展方法感觉是最好的解决方案。
我认为一个合适的解决方案是使用abstract class
而不是interface
。
你在这里分享的是一个通用的验证逻辑,它将对任何实现IMyItem
的类有效。因此,我建议您创建一个abstract class
作为所有项目的基础,这样它们都可以重用该验证代码。您甚至可以将这些属性设置为虚拟的,这样就可以扩展验证代码:
public abstract class ItemBase : IMyItem
{
public string cTitle { get; set; }
public string cDescription { get; set; }
public virtual bool Error
{
get { return TitleError || DescriptionError; }
}
public virtual bool TitleError
{
get { return string.IsNullOrEmpty(cTitle); }
}
public virtual bool DescriptionError
{
get { return string.IsNullOrEmpty(cDescription); }
}
}
你好像在重新发明轮子。微软已经创建了一个相当好的验证框架,它不需要实体框架或MVC。只需将System.ComponentModel.DataAnnotations
和using System.ComponentModel.DataAnnotations
的引用添加到类中:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public class Program
{
public static void Main()
{
// required if you use the MetdataType attribute
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(MyItem),
typeof(IMyItemValidation)),
typeof(MyItem));
var item = new MyItem();
var context = new ValidationContext(item,
serviceProvider: null,
items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(item, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
Console.ReadKey();
}
[MetadataType(typeof(IMyItemValidation))]
public class MyItem : IMyItem
{
public string cTitle { get; set; }
public string cDescription { get; set; }
}
public interface IMyItem
{
string cTitle { get; set; }
string cDescription { get; set; }
}
public interface IMyItemValidation
{
[Required]
string cTitle { get; set; }
[Required]
string cDescription { get; set; }
}
/*
// alternatively you could do either of these as well:
// Derive MyItem : MyItemBase
// contains the logic on the base class
public abstract MyItemBase
[Required]
public string cTitle { get; set; }
[Required]
public string cDescription { get; set; }
}
// or
// Derive MyItem : MyItemBase
// contains the logic on the base class using MetadataType
[MetadataType(typeof(IMyItemValidation))]
public abstract MyItemBase
public string cTitle { get; set; }
public string cDescription { get; set; }
}
}
输出cTitle字段是必需的。
cDescription字段是必需的