2017-02-22 20 views
1

Мне нужно сравнить объекты разных типов, которые, как я знаю, имеют свойства Id и Legacy_id. К сожалению, я не могу добавить к ним интерфейс, поскольку типы берутся из схемы базы данных. Я надеялся, что следующий компаратор будет работать:Почему тип ввода не определяет автоматически, что свойство существует по типу?

type Comparer<'T >()= 
    interface System.Collections.Generic.IEqualityComparer<'T> with 
    member this.Equals (o1:'T,o2:'T)= 
     o1.Legacy_id=o2.Legacy_id 
    member this.GetHashCode(o:'T)= 
     o.Id+o.Legacy_id 

Также у меня есть экземпляры типа сравнения с типами. Итак, теоретически компилятор имеет достаточно информации.

Но это дает ошибку: «Поиск объекта неопределенного типа на основе информации до этой точки программы. Аннотации типа могут потребоваться до этой точки программы, чтобы ограничить тип объекта. Это может позволить поиск для решения ».

Интересно, почему здесь F # не работает? Существуют ли какие-либо реальные/теоретические ограничения или они просто не реализованы? Такой вывод может быть очень полезным.

Я подозреваю, что объяснение о компиляторе F # только вперед. Ограничения C# не имеют. Об этом жалуется сообщение об ошибке. Это так?

+2

Это не может быть скомпилировано, потому что у любого заданного '' T' не гарантируется наличие свойства с именем 'Id'. Вот мысленный эксперимент: что произойдет, если вы создадите этот класс как «Comparer '? –

+0

@FyodorSoikin Но я не копирую его как Comparer . Поэтому, пока я не создам экземпляр с правильными типами, компиляция может работать. – alehro

+0

По-прежнему пытайтесь представить: что, по-вашему, должно произойти, если вы попробуете 'int'? –

ответ

6

Ограничения для членов не могут использоваться для типов, поэтому вы не можете этого сделать. См. here.

Что вы можете сделать, это создать класс сравнения, который принимает явную функцию генерации равенства и хеш-кода для определенного типа, например.

type Comparer<'T>(equalityFunc, hashFunc) = 
    interface System.Collections.Generic.IEqualityComparer<'T> with 
    member this.Equals (o1:'T,o2:'T)= 
     equalityFunc o1 o2 
    member this.GetHashCode(o:'T)= 
     hashFunc o 

Тогда вы могли бы использовать встроенную функцию для создания экземпляров выше для типов, которые соответствуют ограничениям вы хотите ввести:

let inline id obj = 
    (^T : (member Id : int) (obj)) 

let inline legacyId obj = 
    (^T : (member Legacy_id : int) (obj)) 

let inline equals o1 o2 = 
    id o1 = id o2 

let inline hash o = 
    id o + legacyId o 

let inline createComparer< ^T when ^T : (member Id: int) and ^T : (member Legacy_id : int) >() = 
    Comparer<^T>(equals, hash) :> System.Collections.Generic.IEqualityComparer<^T> 

Скажет, у вас есть некоторый тип TestType, который имеет два необходимых свойства :

type TestType = 
    member this.Legacy_id = 7 
    member this.Id = 9 

затем можно сделать, например, createComparer<TestType>() для создания компаратора равенства, соответствующий вашего типа.

+0

Итак, общие типы в C# не статически компилируются. Мне всегда было интересно, почему невозможно манипулировать типами, например, на C++. Кажется, я понимаю. Итак, имея F # 's^T, я могу надеяться переопределить материал метапрограммирования шаблона Aleksandrescu в F # J – alehro

+3

Параметры статического разрешения @alehro F # по-прежнему значительно менее гибкие, чем шаблоны C++. Например, нет возможности параметризовать значения, например, с помощью, например, 'template ', однако они позволяют такие вещи, как моделирование более высокого сорта полиморфизма. – TheInnerLight

5

Конкретный способ получения компаратора, например. создавая HashSet является:

let inline getId o = (^T : (member Id : int) o) 
let inline getLegacyId o = (^T : (member Legacy_id : int) o) 

let inline legacyComparer< ^T when ^T : (member Id : int) and ^T : (member Legacy_id : int)>() = 
    { new System.Collections.Generic.IEqualityComparer<'T> with 
      member __.GetHashCode o = getId o + getLegacyId o 
      member __.Equals(o1, o2) = getLegacyId o1 = getLegacyId o2 } 

Тип умозаключение о выводя с типа, не доказывает, что некоторые общие удовлетворяет параметр типа произвольные условий для всех конкретизации (см номинальных систем vs. структурных типа). Есть много хороших ответов на статически разрешенные параметры типа на SO уже.

 Смежные вопросы

  • Нет связанных вопросов^_^