2016-04-20 4 views
1

У меня есть несколько классов и интерфейсов в моем SDK:C# создать экземпляр загруженного типа derivied от общего типа

public interface IUser 
    { 
     string Name { get; set; } 
    } 

    public abstract class SettingsBase<TUser> where TUser : IUser 
    { 
     public ObservableCollection<TUser> Users { get; set; } 
    } 

    public abstract class Page<TUser> where TUser : IUser 
    { 
     public SettingsBase<TUser> Settings { get; set; } 
    } 

У меня есть DLL-библиотеку с общественными классами:

public class ConfigPage : Page<User> 
{ 

} 

public class User : IUser 
{ 
    public string Name { get; set; } 
} 

public class Settings : SettingsBase<User> 
{ 
    private int _additionalSetting; 
} 

Я хочу проверить, если .dll имеет класс ConfigPage, derivied из страницы:

var dll = Assembly.LoadFrom(@"libraryName.dll"); 
var type = dll.GetExportedTypes().FirstOrDefault(t => t.Name == "ConfigPage"); // the type is Page<User> 
var isIUser = type.BaseType.GetGenericArguments()[0].GetInterfaces().Contains(typeof(IUser)); 

хорошо, все хорошо, но в конце концов мой вопрос is:

Как получить доступ к настройкам SettingsBase Settings?

Почему это возвращает null? :

Activator.CreateInstance(type) as Page<IUser> // type is Page<User>, User implement IUser 
+0

вы не можете бросить тип страницу попытаться привести его к странице

+0

@MahdiFarhani Я думаю, точка OP не знает конкретного типа «Пользователь» - они просто знают свой «IUser» – Jamiec

+0

@up. Точно, SDK не знает класс пользователя. –

ответ

2

Причина null литым результата является то, что общие классы инвариантной - вы не можете назначить экземпляр MyClass<Base> переменный типа MyClass<Derived> или наоборот.

Я предлагаю вам обновить свои интерфейсы с interfaces-covariance:

public interface IUser { 
    string Name { get; set; } 
} 
public interface ISettings<out TUser> 
    where TUser : IUser { 
    IEnumerable<TUser> Users { get; } 
} 
public interface IPage<out TUser> 
    where TUser : IUser { 
    ISettings<TUser> Settings { get; } 
} 

// Abstract implementation 
public abstract class SettingsBase<TUser> : ISettings<TUser 
    where TUser : IUser { 
    public SettingsBase() { 
     Users = new ObservableCollection<TUser>(); 
    } 
    public IEnumerable<TUser> Users { get; private set; } 
} 
public abstract class Page<TUser> : IPage<TUser> 
    where TUser : IUser { 
    public Page() { 
     Settings = CreateSettings(); 
    } 
    public ISettings<TUser> Settings { get; private set; } 
    // 
    protected abstract ISettings<TUser> CreateSettings(); 
} 
// Real implementation 
public class ConfigPage : Page<User> { 
    protected override ISettings<User> CreateSettings() { 
     return new Settings(); 
    } 
} 
public class User : IUser { 
    public string Name { get; set; } 
} 
public class Settings : SettingsBase<User> { 
    // ... 
} 

Использование:

IPage<IUser> page = Activator.CreateInstance(typeof(ConfigPage)) as IPage<IUser>; 
+0

Это была моя первая мысль - я изо всех сил пытался получить пример, демонстрирующий в ответ: http://rextester.com/MNPMF82191 Я думаю, что это требует больше, чем вы показали в этом ответе. – Jamiec

+0

как Jamiec сказал ... Я получаю (26:32) Неверная дисперсия: параметр типа «TUser» должен быть неизменно действительным на «Rextester.IPage .Settings». «TUser» ковариантен. (31:40) Неверная дисперсия: параметр типа «TUser» должен быть инвариантным на «Rextester.ISettingsBase .Users». «TUser» ковариантен. –

+0

Пожалуйста, проверьте фрагмент кода в моем обновленном ответе - он демонстрирует рабочий код (вы должны опустить «мутаторы» в цепочке интерфейсов). – DmitryG

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