Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
101 views
in Technique[技术] by (71.8m points)

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

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.

question from:https://stackoverflow.com/questions/65672073/create-a-class-to-store-classes-that-use-different-interfaces

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...