简体   繁体   中英

C# create instance of loaded type derivied from generic type

I have few classes and interfaces in my SDK:

    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; }
    }

I have a .dll library with public classes:

public class ConfigPage : Page<User> 
{

}

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

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

I want to check if .dll has ConfigPage class, derivied from Page :

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));

Ok, everything is good, but finally my question is:

How to get access to SettingsBase Settings property?

Why this returning null? :

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

The reason of null cast-result is a fact, that generic classes are invariant - you cannot assign an instance of MyClass<Base> to a variable of type MyClass<Derived> or vice versa.

I suggest you to update your interfaces with the 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> {
    // ...
}

Usage:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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