繁体   English   中英

通用类型约束和方差

[英]Generic type constraint and variance

我正在构建一个类似于AutoMapper的简单类型映射器,但具有更动态的行为。 从实体框架模型映射时,调用者可以决定过滤RecordStatus == RecordStatus.Deleted记录。

抽象映射器:

public interface IMapper<in TIn, out TOut>
{
    TOut Map(TIn input);
}

public interface IRecordStatusFilterable
{
    string RecordStatus { get; }
}

public abstract class RecordStatusFilterableMapperBase<TIn, TOut> : IMapper<TIn, TOut>
{
    private readonly bool _filterDeletedRecords;

    protected RecordStatusFilterableMapperBase(bool filterDeletedRecords)
    {
        _filterDeletedRecords = filterDeletedRecords;
    }

    protected bool FilterDeletedRecords
    {
         get { return _filterDeletedRecords; }
    }

    public abstract TOut Map(TIn input);
}

public class MultiLookupValuesMapper : RecordStatusFilterableMapperBase<IEnumerable<Lookup>, string>
{
    private static readonly Func<Lookup, bool> _predicate = 
        filterable => filterable.RecordStatus == RecordStatus.Active;

    protected MultiLookupValuesMapper(bool filterDeletedRecords) : base(filterDeletedRecords)
    {
    }

    public override string Map(IEnumerable<Lookup> input)
    {
        var inputList = input as IList<Lookup> ?? input.ToList();
        if (!inputList.Any())
        {
            return string.Empty;
        }

        if (FilterDeletedRecords)
        {
            inputList = (IList<Lookup>)inputList.Where(_predicate);
        }

        return string.Join(", ", inputList.Select(l => l.Value));
    }
} 

具体的映射器:

public class FooMapper<TRecordStatusFilterable> : RecordStatusFilterableMapperBase<Foo, FooViewModel> 
    where TRecordStatusFilterable : class, IRecordStatusFilterable
{
    private readonly IMapper<IEnumerable<TRecordStatusFilterable>, string> _multiLookupValueMapper;

    public FooMapper(IMapper<IEnumerable<TRecordStatusFilterable>, string> multiLookupValueMapper,
                     bool filterDeletedRecords) : base(filterDeletedRecords)
    {
        _multiLookupValueMapper = multiLookupValueMapper;
    }

    public override FooViewModel Map(Foo input)
    {
        return new FooViewModel
        {
            // Error here
            BarLookupValues = _multiLookupValueMapper.Map(input.Lookups)
        };
    }
}

实体框架模型:

public class Foo
{
    public ICollection<Lookup> Lookups { get; set; }
}

public class Lookup : IRecordStatusFilterable
{
    public string Value { get; set; }

    public string RecordStatus { get; set; }
}

的ViewModels:

public class FooViewModel
{
    // ICollection<Lookup> => string
    public string BarLookupValues { get; set; }
}

我收到一个编译错误:

参数1:无法从“ System.Collections.Generic.IEnumerable <查找>”转换为“ System.Collections.Generic.IEnumerable <TRecordStatusFilterable>”

但是我的Lookup类确实实现了通用类型参数约束,因为它实现了IRecordStatusFilterable 谁能对此有所启发?

实际上,许多代码与实际问题无关。 这是一个更简单的版本,希望可以更好地说明它:

class MyList<T>
    where T : class, IConvertible
{
    private List<T> list = new List<T>();

    public void Add(string s)
    {
        list.Add(s); // error
    }        
}

是的, T是受约束的,并且string符合约束,但这并不意味着您可以将string添加到任意T的列表中。 那不会输入安全。

如果我定义

class Bar : IConvertible { /* left out IConvertible impl */ }

并使var bars = new MyList<Bar>()很明显,将字符串添加到bar是泛型类中该代码的问题。

您刚刚得到了一个更复杂的版本,而我不确定100%确实要表达什么。 也许类FooMapper根本不应该是泛型的,而应该仅接受IMapper<IEnumerable<Lookup>, string>的实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM