代码之家  ›  专栏  ›  技术社区  ›  Dmitry Volkov

未指定泛型属性的比较

  •  0
  • Dmitry Volkov  · 技术社区  · 9 年前

    考虑以下代码:

    public interface IIdentifiable<T>
    {
        T Id { get; set; }
    }
    
    public interface IViewModel
    {
    }
    
    public class MyViewModel1 : IViewModel, IIdentifiable<int>
    {
        public string MyProperty { get; set; }
    
        public int Id { get; set; }
    }
    
    public class MyViewModel2 : IViewModel, IIdentifiable<string>
    {
        public string MyProperty { get; set; }
    
        public string Id { get; set; }
    }
    

    public class Loader<T> where T: IViewModel
    {
        public void LoadData()
        {
            /*some important stuff here*/
    
            if (typeof(IIdentifiable<??>).IsAssignableFrom(typeof(T)))
            {                     // ^- here's the first problem
                data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<??>) ds).Id != ((IIdentifiable<??>) d).Id)).ToList();
            }                                                             // ^---- and there the second ----^
    
            /*some important stuff here too*/
        }
    }
    

    现在,如您所见,我的viewmodels可能实现 IIdentifiable<> 我想确定我的 data 列表中不包含我的 _dataSourse

    我有两个问题:

    1. 可识别<&燃气轮机; int , string GUID typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) 这是正确的语法,但它总是返回 false . T 可识别<&燃气轮机; 不知道确切的泛型类型?

    2. 如果第一个问题有答案,我也想知道如何比较 Id 我找到了 this answer 非常有用,但它不包括我的

    我知道,如果我能 Loader<T> Loader<T,K> 哪里 K 将是 输入 可识别<&燃气轮机; ,但我想知道是否还有其他解决方案。


    类型(可识别<)。IsAssignableFrom(typeof(T)) 可识别<&燃气轮机; 是否未指定?


    编辑: 我想,事后来看,我理解为什么我不能这么直截了当地编写代码——因为可能有收藏 ICollection<IViewModel> 可识别<&燃气轮机; Loader ?

    3 回复  |  直到 9 年前
        1
  •  1
  •   Aleks Andreev Md. Suman Kabir    9 年前

    尝试将两种方法添加到 Loader<T> :

    public bool CanCast<TId>()
    {
        var identifiableT = typeof(IIdentifiable<>).MakeGenericType(typeof(TId));
        return identifiableT.IsAssignableFrom(typeof(T));
    }
    
    public IEnumerable<IIdentifiable<TId>> Filter<TId>(IEnumerable<T> data)
    {
        return data.Where(d => _dataSource.All(
          ds => !((IIdentifiable<TId>) ds).Id.Equals(((IIdentifiable<TId>) d).Id)));
    }
    

    然后在 LoadData

    if (CanCast<int>())
        data = Filter<int>(data);
    else if (CanCast<Guid>())
        data = Filter<Guid>(data);
    // and so om
    
        2
  •  1
  •   Phil1970    9 年前

    然而,我确实认为你的算法的性能会很差,因为你基本上会循环2个容器,所以它会是O(n*m)。

    因此,如果两个源都来自数据库,则最好执行适当的SQL查询,如果在代码中执行,则最好使用字典。或者,如果数据排序正确,您可以更有效地找到重复项。

    顺便说一句,泛型在C语言中相当有限#

        3
  •  1
  •   Tanveer Badar    9 年前

    我们应该分两步来解决你的问题(因为这里确实有两个问题需要解决)。

    首先,对界面进行以下更改 IIdentifiable<T>

    public interface IIdentifiable<T>
        where T : IEquatable<T>
    {
        T Id { get; set; }
    }
    

    其次,在你的 LoadData() 方法,更改 if

        if (T is IIdentifiable<T>)
        {                     // ^- here's the first problem
            data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<T) ds).Id != ((IIdentifiable<T) d).Id)).ToList();
        }