有没有办法在不使用扩展方法的情况下扩展接口?
如果我用一些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
得到/集 - 有没有办法实现相同但暴露
获取/设置属性而不是扩展方法?
正如许多人所建议的,基于该示例,abstract
类将是一个明显的解决方案,但类型需要实现多个接口。
虽然可以安排继承,但这是对类型的不必要的复杂性和限制。
使用扩展方法对这些接口进行验证的额外好处允许特定于上下文的&通过命名空间共享逻辑。
可以在不同的名称空间上为接口定义多个ERROR(this IMyItem item)
扩展方法。检查TITLE_ERROR
和DESCRIPTION_ERROR
以及另一个可能只测试其中一个属性的人。然后,根据上下文,可以引用相关的命名空间,并执行该项的共享验证。
我会看看微软的验证器,但它看起来相当冗长,我真的希望这些状态作为类型的属性,因为它使得使用它们的代码更容易使用。
此外,这些是非常简单的示例,一些验证要复杂得多,有些情况需要与其他Web服务交互 - 尽管AppDomain中的Web服务数据缓存。
目前,这些
interface
扩展方法感觉是最佳解决方案。
答案 0 :(得分:5)
我认为合适的解决方案是使用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); }
}
}
答案 1 :(得分:0)
好像你正在重新发明轮子。 Microsoft已经创建了一个不需要Entity Framework或MVC的公平good validation framework。只需将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字段是必需的。