Thomas Segato
Thomas Segato

Reputation: 5275

How to instantiate generic classes

I have an interface:

public interface ICrawlService<T> where T : SocialPostBase
{
    Task<int> Crawl(int accountId, Disguise disguise, ISocialAccountRepository socialAccountRepository, ISocialRepository<T> socialRepository, ISocialCrawlJobRepository jobRepository, IInstrumentationRepository instrumentationRepository);
}

My social repository is:

public interface ISocialRepository<T> where T : class
{
    IEnumerable<SocialPostCollection<T>> List { get; }
    Task Add(SocialPostCollection<T> entity, string type);

    Task AddPosts(List<T> entity, string type);

    void Delete(SocialPostCollection<T> entity);
    void Update(SocialPostCollection<T> entity);
    T Find(string profileName, MediaType type);
}

I am looking for a polymorphic design so I can instantiate different classes into a single type. Something like:

var socialRepo = new SocialRepository<Video>(configration.CosmosDBServiceEndpoint, configration.CosmosDBSecret, configration.CosmosDBDatabaseId);
var socialRepo2 = new SocialRepository<Post>(configration.CosmosDBServiceEndpoint, configration.CosmosDBSecret, configration.CosmosDBDatabaseId);

ICrawlService<SocialPostBase> crawlService;

crawlService = new CrawlYoutubeProfileService();
var id = await crawlService.Crawl(jobId, null, _socialAccountRepo, socialRepo, _socialCrawlJobRepo, instrumentationRepo);

crawlService = new CrawlAnotherProfileService();
var id2 = await crawlService.Crawl(jobId, null, _socialAccountRepo, socialRepo2, _socialCrawlJobRepo, instrumentationRepo);

However it will not accept the base class for the generic parameter, I get following error.

Cannot implicitly convert type 'SocialCrawlServices.CrawlYoutubeProfileService' to 'SocialCrawlServices.ICrawlService'. An explicit conversion exists (are you missing a cast?)

So how do you make a generic polymorphic design? Is that not possible?

Upvotes: 0

Views: 64

Answers (2)

jasonmchoe
jasonmchoe

Reputation: 491

The error says "An explicit conversion exists (are you missing a cast?)". The answer is to explicitly cast the implementing class as the interface:

crawlService = (ICrawlService<SocialPostBase>)new CrawlYoutubeProfileService();

crawlService = (ICrawlService<SocialPostBase>)new CrawlAnotherProfileService();

This should work as long as CrawlYoutubeProfileService and CrawlAnotherProfileService have type arguments that implement SocialPostBase, like this:

class YoutubePost : SocialPostBase
{

}

class CrawlYoutubeProfileService : ICrawlService<YoutubePost>
{

}

Upvotes: 0

Aly Elhaddad
Aly Elhaddad

Reputation: 1953

Is that not possible?

No, it's possible. You just need to add out before your generic parameter in ICrawlService.

public interface ICrawlService<out T> where T : SocialPostBase

See Covariance and Contravariance in Generics.

Upvotes: 1

Related Questions