是否有一种设计模式可以避免这种重复或反射?

时间:2014-10-13 15:52:40

标签: c# entity-framework design-patterns reflection

情况:

我有一些代码可以是:

  • a)表现不佳(反思)
  • b)重复
  • c)难以(维持)

我希望有一种方法可以获得可维护的非重复代码,而这些代码没有反映出来的性能。

a)一个性能欺诈功能。

static public SelectListItem ToSelectListItem(this Object item, string textProperty, string valueProperty, bool isSelected)
{
    return new SelectListItem()
    {
        Selected = false,
        Text = item.GetType().GetProperty(textProperty).GetValue(item, null),
        Value = item.GetType().GetProperty(valueProperty).GetValue(item, null)
    };
}

b) 12个代码90%相似的函数。

static public SelectListItem ToSelectListItem(this Class1 type)
{
    return new SelectListItem()
    {
        Selected = false,
        Text = type.Name,
        Value = type.LoadInfoTypeID.ToString() // This ID is the only thing that changes.
    };
}

c) 1需要稍微难以维护编码的功能。

static public SelectListItem ToSelectListItem(this Object type)
{
    int ID = type is Class1 ? (type as Class1).SomeID :
             type is Class2 ? (type as Class2).AnotherID :
             type is ClassN ? (type as ClassN).YetAnotherID :
             -1;
    return new SelectListItem()
    {
        Selected = false,
        Text = type.Name, // Ignore the fact that Object doesn't technically have a Name Prop for the moment.
        Value = ID.ToString()
    };
}

问题

上面的代码是否有一种更可维护的非重复方式,不会抑制性能(至少不会过度)?

情况c)如果我必须使用它是可以接受的,但我想知道是否有任何我不知道的替代方案。

这些类(Class1,Class2等)是 Entity-Framework中的实体。我不确定是否添加/删除任何可用选项。

5 个答案:

答案 0 :(得分:4)

让有问题的类符合特定的接口,允许根据需要采用通用的数据操作方式。

该接口提供了一个合同,未来的程序员可以理解该合同进行维护,并允许在反射操作之外处理实例的类型一致的方式。

似乎有一种被认可的模式;因此,使用此设计仅适用于现有流程。辅助接口(?)可以处理其他处理的其他实例,即5%。

答案 1 :(得分:1)

你有几个选择(没有像AutoMapper这样的第三方库为你做这种事情。)

可以使用类上的接口并将其传递给(参见OmegaMan's answer

另一种选择是使用一个函数,它接受一些代表来决定要使用的类型。

static public SelectListItem ToSelectListItem<TItem>(this TItem type, Func<TItem, string> nameSelector, Func<Titem, string> valueSelector)
{

    return new SelectListItem()
    {
        Selected = false,
        Text = nameSelector(type)
        Value = valueSelector(type)
    };
}

//elsewhere
Class1 item1 = ...
item1.ToSelectListItem(a=>a.Name, a=>a.SomeId);
Class2 item2 = ...
item2.ToSelectListItem(a=>a.Name, a=>a.AnotherID);
ClassN itemN = ...
itemN.ToSelectListItem(a=>a.Name, a=>a.YetAnotherID);

答案 2 :(得分:1)

也许类似于a)的解决方案但没有反射就足够了?另外,您不必使用字符串名称来引用属性。

public static SelectListItem<T>(T o, Func<T, string> textFunc, Func<T, string> valueFunc)
{
    return new SelectListItem
        {
            Selected = false,
            Text = textFunc(o),
            Value = valueFunc(o)
        }

}

答案 3 :(得分:1)

您可以在EF生成的代码中添加属性。大多数模板为此目的生成部分。所以你可以:

public interface ITextValue
{
    string GetValue();
    string GetText();
}

// for each entity
public partial class SomeEntity : ITextValue // this for each EF-type
{
    public GetValue() { return this.ID.ToString(); }
    public GetValue() { return this.Name; }
}

然后

static public SelectListItem ToSelectListItem(this ITextValue obj)
{
    return new SelectListItem()
    {
        Selected = false,
        Text = obj.GetText(),
        Value = obj.GetValue()
    };
}

但是,如果您不想修改EF类型,可以使用此方法:

public interface ITextValue
{
    string GetValue(object obj);
    string GetText(object obj);
}

// for each entity
public class SomeEntityReader : ITextValue // this for each EF-type
{
    public GetValue(object obj) { return ((SomeEntity).ID).ToString(); }
    public GetValue(object obj) { return ((SomeEntity)this).Name; }
}

// somewhere central
var Readers = new Dictionary<Type,ITextValue>()
Readers.Add(typeof(SomeEntity), new SomeEntityReader());
// etc

然后

static public SelectListItem ToSelectListItem(this object item)
{
    var reader = Readers(typeof(item));
    return new SelectListItem()
    {
        Selected = false,
        Text = reader.GetText(),
        Value = reader.GetValue()
    };
}

答案 4 :(得分:0)

我建议让你的类派生自一些基类,它会暴露一些将被覆盖的ID字段或方法GetId

public abstract class YourAbstractClass 
{
    public abstract int ID { get; set; }
}

public class ConcreteClass1 : YourAbstractClass
{
    public override int ID
    { 
        get { return SomeID } 
        set { SomeID = value } 
    }
}

如果属性,您可能需要使用ID装饰NotMappedAttribute