Create a class to store classes that use different interfaces - c#

I am working on a project in C# which needs to store information about a user. This information is retrieved from their respective libraries which have their own implementations and interfaces. Currently users can either connect from Twitch or Discord, so they will be represented as either TwitchUser or DiscordUser objects. However, I would like to write a class User that will contain one of the 2 classes which should make it easier for me to refer to them in code.
Here is an example of how TwitchUser and DiscordUser look like:
public class TwitchUser : IChatUser
{
public TwitchUser();
public string Id { get; }
public string UserName { get; }
public string DisplayName { get; }
public string Color { get; }
//and so on...
}
public class DiscordUser : SnowflakeObject, IEquatable<DiscordUser>
{
public virtual string Email { get; internal set; }
public virtual string Username { get; internal set; }
public bool Equals(DiscordUser e);
//and so on...
}
I thought I could create a class which accepts generic types but with my implementation I would have to pass BOTH classes which means one of them would be null. This doesn't feel right to me.
public class User<T,D>
{
public TwitchUser VarA { get; set; }
public DiscordUser VarB { get; set; }
}
What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?
I would then also write code inside my User class to return user IDs etc.
Update
For example, when I request a user ID I would perform a check inside User whether I stored a TwitchUser or DiscordUser, and based on the outcome I would return an attribute which represents the user's ID on that platform.
Update 2
A user may only be represented by one of the two classes. For example, if they used Discord as their platform to login then they will only have a DiscordUser object associated with them. Same applies to Twitch platform and it using TwitchUser object. The reason they are different is because these implementation were written by different people using 2 different libraries, which is why they don't use the same interfaces, or inherit from one common class. So what I am trying to do is retroactively add some sort of an inheritance here. This way, when I want to refer to the user in my code, I don't need to write 2 overloads for a function (where one uses TwitchUser and the other uses DiscordUser). I just want to be able to refer to User and let that class decide for me.

those 2 clases I mentioned cannot be modified [...] I want to be able to access all the necessary attributes stored in DiscordUser and TwitchUser
That sounds like a good fit for the adapter pattern. Define an interface as common denominator:
public interface IUser
{
string Id { get; }
string Username { get; }
}
Note that this interface can only contain properties that both objects share, or you're going to need null checks all over the place.
Then create an adapter for each type you want to wrap:
public class TwitchUserAdapter : IUser
{
private readonly TwitchUser _user;
public TwitchUserAdapter(TwitchUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.UserName;
}
public class DiscordUserAdapter : IUser
{
private readonly DiscordUser _user;
public TwitchUserAdapter(DiscordUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.Username;
}
Now you can treat both the same:
var users = new List<IUser>();
users.Add(new TwitchUserAdapter(new TwitchUser { Id = "Tfoo", UserName = "Tbar" }));
users.Add(new DiscordUserAdapter(new DiscordUser { Id = "Dfoo", Username = "Dbar" }));
foreach (var user in users)
{
Console.WriteLine($"Id: {user.Id}, Name: {user.Username}");
}

"What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?"
One way to accomplish this might be to create a class that contains all the properties you care about, and then create static methods that return an instance of the class based on the properties of a TwitchUser or a DiscordUser:
public class User
{
// Add just the properties you care about
public string Id { get; private set; }
public string UserName { get; private set; }
public string DisplayName { get; private set; }
public string Color { get; private set; }
public string Email { get; private set; }
// Make the default constructor private so instances of this
// class can only be created from one of our static methods
private User() { }
public static User FromTwitch(TwitchUser twitchUser)
{
return new User
{
Id = twitchUser.Id,
Color = twitchUser.Color,
DisplayName = twitchUser.DisplayName,
UserName = twitchUser.UserName
};
}
public static User FromDiscord(DiscordUser discordUser)
{
return new User
{
Email = discordUser.Email,
UserName = discordUser.Username
};
}
}

Related

ASP.NET: How can I configure the get and set of an object that belongs to a custom class?

How can I configure the get and set of an object that belongs to a custom class?
I have the following situation (and it’s not working):
public class SurveyETA
{
public static string Question1 { get; set; }
public static string Question2 { get; set; }
public static string Question3 { get; set; }
public static string Question4 { get; set; }
public static string Question5 { get; set; }
public static string Question6 { get; set; }
}
public static SurveyETA RespondentETA = new SurveyETA()
{
Question1 {
get { return HttpContext.Current.Session["RespondentQ1"] == null ? "" : HttpContext.Current.Session["jSession326"].ToString();}
set { HttpContext.Current.Session["RespondentQ1"] = value; }}
};
My intention is that this object has properties whose content is unique and specific to each user. If I only use a static instance, what happens is that all users share the content.
There really isn't enough information here to answer your particular question about your particular situation.
That said, I can attempt to make some assumptions about what you may want to consider based on what you're saying.
You talk about having individual users. Where are those users stored? If they're stored in a database, then you can use queries against that database to return information that is specific to those users.
The specific information you have about those users will also be stored in your database, and that information will be associated with those users through the user id for each user (among other things. This is a very high level overview of how this works).
TL;DR:
Query whatever database storage mechanism you're using to get the information you need for each user. Return that information and associate it with an instance of your SurveyETA class.

Is is good practice to have same type of list in a class?

I have created a class and I'm putting a list of same type as a property of that class.
Is it good or bad practice?
I am putting the same type of list because of I want to manage everything by only one object.
I don't want to create a single object and a list of object of the same type.
Any help is highly appreciated!
class AssetSection
{
public string Code { get; set; }
public string Description { get; set; }
public string SITEID { get; set; }
public string PlantID { get; set; }
public string User { get; set; }
public string UpDateTime { get; set; }
public List<AssetSection> AssetSections { get; set; }
public AssetSection(string des, string code)
{
Description = des;
Code = code;
}
}
That's ok. If you can imagine, you can design and use it.
Let's talk about entity framework. We create 2 entities like this:
public class User : IdentityUser
{
[Key]
public string Id { get; set; }
public UserProfile Profile { get; set; }
}
public class UserProfile
{
[Key]
public string UserId { get; set; }
public User User { get; set; }
}
Now, when we try to get current user:
User user = await _userManager.GetUserAsync(User);
user becomes an instance of User class now. This instance has a property name Profile, and this property has another property name User which has a type User.
It's called mapping. So, to answer your question: You can use it. But I'm not saying it's good or not based on the way to design the model.
As a general observation, such a structure is known as a rose tree, or just a tree. It enables you to write code like this:
var t = new AssetSection("foo", "bar")
{
AssetSections = new List<AssetSection>
{
new AssetSection("baz", "qux")
{
new AssetSection("corge", "garply"),
new AssetSection("fred", "plugh")
{
AssetSections = new List<AssetSection>
{
new AssetSection("xyzzy", "thud")
}
}
},
new AssetSection("quux", "quuz")
{
new AssetSection("grault", "waldo")
}
}
};
If what you want to model is a tree-like structure like that, then it's fine. On the other hand, if such a hierarchy is not what you're trying to model, then it's likely to be confusing.
By the way, the code as proposed violates the .NET framework design guidelines:
DO NOT provide settable collection properties.
DO NOT use ArrayList or List<T> in public APIs

Model validation, database constraints

I'm trying to add some architecture to my projects and enrich my models.
I started with CQS (implementation similar to that one: CQS-Sample) and here's my first problem.
Let's say I have two classes like these below:
public class Network
{
public int Id { get; set; }
public User User { get; set; }
private IQueryFactory _queryFactory { get; set; }
public Network(IQueryFactory queryFactory)
{
_queryFactory = queryFactory;
}
public void AddUser(User user)
{
if(this.User == null && user != null)
{
userHasUniqueEmail(user);
this.User = user;
}
}
private void userHasUniqueEmail(User user)
{
bool isUnique = _queryFactory.ResolveQuery<INewUserUniqueQuery>().Execute(user.Email);
if (!isUnique)
{
throw new ArgumentException("E-mail is not unique");
}
}
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}
Network object can have User, but I need to check first in database that given e-mail doesn't already exists or do some other checkings, so my commands will be executed successfully.
By adding user I mean adding completely new User to database.
Would it be correct way to do this?
You can do it the way you do it now and it's ok.
Another option is to make this Validation in Contoller. Then you should use Remote attribute. And Move your IsEmailUnique(string mail) method to Controller.
If you want to know how you can do it with email check - this question will help you.

File Indexing software - Design

I am currently developing a file indexing system. I have an interface IDiskDrive that can get immediate file items (files/folders). The interface definition is as follows...
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
The ability to read all file/folders is complete and works correctly. Now, I need to actually index the file files and folders. Looking ahead I know I will need some reporting tools. This leads me to think I need another abstraction, based upon IDiskDrive that can read/populate. I also need the ability to select drives for indexing.
My question is should my new class inherit IDiskDrive or should I use composition (possibly a decorator)?
// inheritance
class IndexedDiskDrive : IDiskDrive
{
public IndexedDiskDrive(IDiskDrive drive)
{
...
}
public int Id {get; internal set; } // database id
public bool Selected { get; internal set; }
public DateTime? DateLastIndexed { get; internal set; }
// IDiskDrive implementation
public bool IsReady
{
get { return this.Drive.IsReady; }
}
}
or composition...
class IndexedDiskDrive
{
public IndexDiskDrive(IDiskDrive drive)
{
this.Value = drive;
}
public IDiskDrive Value
{
get;
private set;
}
// additional properties
public int Id { get; internal set; }
public bool Selected { get; internal set;}
public DateTime DateLastIndexed { get; internal set; }
}
Note:
I need access to the underlying IDiskDrive for the UI.
For example, I request user to select drives to index. I initially supply a list of local drives and the ability to add network drives. To try and keep code simple, I thought the idea of a new class with a selected property might help.
This allows the GUI to enumerate a list of IndexedDiskDrives and set/clear the select property.
In both examples you expose the IDiskDrive object from the other object. In the first case you inherit from the same inteface, which means you expose the same methods and in the other case you expose the object via a property.
I don't see a reason yet why you want to do this.
It sounds like a typical constructor DI case to me. Just have a new interface for your new class which is doing a different job and hence requires a different contract, and if it needs the IDiskDrive object as a dependency, then just inject it via the constructor and leave it as it is.
P.S.: I know this is not something you have asked, but you might be interested in Lucense.NET, which is a .NET library to index files. They might have already solved your problem for your:
http://lucenenet.apache.org/
EDIT:
From your current class design I would do the following:
void Main()
{
// Use IoC container in real app:
var diskDrive = new DiskDrive(...);
var fileIndexer = new FileIndexer();
var fileItems = diskDrive.GetImmediateFileItems(filePath);
fileIndexer.IndexFiles(fileItems);
}
// Define other methods and classes here
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
public interface IFileIndexer
{
void IndexFiles(IEnumerable<IFileItem> files);
}
public class FileIndexer : IFileIndexer
{
public void IndexFiles(IEnumerable<IFileItem> files)
{
// do stuff
}
}

Facade a class without writing lots of boilerplate code?

Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.

Categories

Resources