问题
I really don't understand as it seems to me the basics of type conformance. I have a Creation instruction lists explicit creation type which does not conform to type of target
on create {JANITZA_DEVICE} l_device.make_from_file_path (a_file_path)
with eiffel studio 19.5 enterprise.
SMA_INVERTER_MANAGER_CSV
class
SMA_INVERTER_MANAGER_CSV
inherit
SUNSPEC_DEVICE_CSV[SMA_INVERTER_MANAGER_DEVICE]
create
make
SUNSPEC_DEVICE_CSV
deferred class
SUNSPEC_DEVICE_CSV[G -> SUNSPEC_DEVICE create make_from_file_path end]
inherit
CONSUMPTION_SECTOR_CSV[G]
redefine
process_file,
set_header_csv
end
feature --
process_file (a_file_path: PATH)
require else
attached a_file_path.entry
attached consumption_sector
local
l_device: like devices.item
do
check
attached_consumption_sector: attached consumption_sector
then
if is_valid_file_path (a_file_path) then
if attached a_file_path.utf_8_name.has_substring ("janitza_UMG604") then
create {JANITZA_DEVICE} l_device.make_from_file_path (a_file_path) -- The compiler doesn't agree!
else
create l_device.make_from_file_path (a_file_path)
end
l_device.load_measuring_point (create_measuring_points, measuring_point_db_service, consumption_sector)
devices.extend (l_device)
Precursor (a_file_path) -- load measure_units from csv_row
devices.wipe_out
end
end
ensure then
devices.is_empty
end
CONSUMPTION_SECTOR_CSV[G]
deferred class
CONSUMPTION_SECTOR_CSV[G -> MEASURING_POINT_DEVICE]
feature -- Access
devices: LINKED_SET[G]
SUNSPEC_DEVICE
class
SUNSPEC_DEVICE
inherit
MEASURING_POINT_DEVICE
redefine
default_create,
set_measuring_point,
out
select
serial
end
MODBUS_DEVICE
rename
serial as modbus_serial,
set_serial as set_modbus_serial
undefine
make
redefine
default_create,
make_from_file_path,
name_from_file_path,
out
select
set_modbus_serial
end
create
make_from_file_path
JANITZA_DEVICE
class
JANITZA_DEVICE
inherit
SUNSPEC_DEVICE
redefine
set_measure_units,
name_from_file_path
end
create
make_from_file_path
回答1:
Here is a simplified case:
class ANIMAL
class CAT inherit ANIMAL
class HOUSE_CAT inherit CAT
class DOG inherit ANIMAL
class
ENCLOSURE [G -> ANIMAL]
feature
specimens: LIST [G] --> The actual type will vary with the generic parameter
describe
do
print(specimens.generating_type)
end
class
APPLICATION
feature
test
local
l_cat: CAT
l_animal_enclosure: ENCLOSURE [ANIMAL]
l_cat_enclosure: ENCLOSURE [CAT]
l_house_cat_enclosure: ENCLOSURE [HOUSE_CAT]
l_dog_enclosure: ENCLOSURE [DOG]
do
create l_specimen
create l_animal_enclosure
l_animal_enclosure.describe --> LIST [ANIMAL]
l_animal_enclosure.specimens.add (l_cat) --> Fine, CAT conforms to ANIMAL
create l_cat_enclosure
l_cat_enclosure.describe --> LIST [CAT]
l_cat_enclosure.specimens.add (l_cat) --> Fine, CAT conforms to CAT
create l_house_cat_enclosure
l_house_cat_enclosure.describe --> LIST [HOUSE_CAT]
l_house_cat_enclosure.specimens.add (l_cat) --> ERROR, CAT does not conform to HOUSE_CAT
create l_dog_enclosure
l_dog_enclosure.describe --> LIST [DOG]
l_dog_enclosure.specimens.add (l_cat) --> ERROR, CAT does not conform to CAT
end
In your case, devices: LINKED_SET [G]
is too vague, nothing proves that JANITZA_DEVICE
is a valid type because G
might end up being lower down the hierarchy (like HOUSE_CAT
-> CAT
; you cannot substitute a CAT
to a HOUSE_CAT
, thus a list of HOUSE_CAT
cannot accommodate a CAT
) or in a separate branch of the hierarchy (like DOG
-> ANIMAL
; a dog is not a cat, they only share a common ancestor).
If {ENCLOSURE}.specimens
was declared as LIST [ANIMAL]
instead of LIST [G]
, describe
would always print LIST [ANIMAL]
regardless of the actual generic parameter because the type would not vary, thus the previous code would compile and run just fine.
Similarly, if {CONSUMPTION_SECTOR_CSV}.devices
was declared as LINKED_SET [SUNSPEC_DEVICE]
instead of LINKED_SET [G]
, it could accommodate all descendants of SUNSPEC_DEVICE
regardless of the actual type of G
.
Alternatively, you could move the parts specific to JANITZA_DEVICE
from CONSUMPTION_SECTOR_CSV
to a descendant of CONSUMPTION_SECTOR_CSV
where G
is closed, as in
class
JANITZA_CONSUMPTION_SECTOR_CSV -- No generic here!
inherit
CONSUMPTION_SECTOR_CSV [JANITZA_DEVICE]
redefine
process_file -- Add the parts specific to `JANITZA_DEVICE` in the implementation
end
which would ensure that devices
can hold instances JANITZA_DEVICE
.
回答2:
I think that user10481525 has explained the reason for the error. Your code doesn't guarantee that JANITZA_DEVICE
will conform to G
in all potential descendants of SUNSPEC_DEVICE_CSV
.
You have declared the attribute devices: LINKED_SET [G]
. Therefore, the local variable l_device: like devices.item
would be of type G
. Attaching a JANITZA_DEVICE
to it might be invalid in a descendant of SUNSPEC_DEVICE_CSV
. Why? Because G
could be any descendant of SUNSPEC_DEVICE
.
For example, suppose you had a descendant class FOO_DEVICE_CSV inherit SUNSPEC_DEVICE_CSV [FOO_DEVICE]
; where class FOO_DEVICE inherit SUNSPEC_DEVICE
. Your local variable would effectively resolve to local l_device: FOO_DEVICE
. Therefore, the descendant would be trying to attach an object of type JANITZA_DEVICE
to it. But that's invalid, because JANITZA_DEVICE
doesn't conform to FOO_DEVICE
:
feature devices: LINKED_SET [FOO_DEVICE]
...
local l_device: FOO_DEVICE
...
create {JANITZA_DEVICE} l_device.make_from_file_path (a_file_path) -- Invalid!
来源:https://stackoverflow.com/questions/58368872/explicit-creation-type-not-conforming-to-type-of-target