简体   繁体   English

通过使用泛型避免在以下代码中进行强制转换

[英]Avoid Casting in following Code by using Generics

I am new to generics and just wondering if it's possible to avoid the casting in the following code using better OO approach. 我是泛型的新手,只是想知道是否可以使用更好的OO方法避免在以下代码中进行转换。

public class CollectorFactory
{
    public static MyCollector Create(ICredential credential)
    {
        return new MyCollector(credential);
    }
}

public class MyCollector {

    public MyCredential Credential { get; set; }

    public MyCollector(ICredential credential)
    {
        this.Credential = (MyCredential)credential;
    }

    public void Show()
    {
        Console.WriteLine(this.Credential.Username);
        Console.WriteLine(this.Credential.AuthToken);
    }
}

public class MyCredential : ICredential
{
    public string Username{ get; set;  }

    public string AuthToken { get; set; }
}

public interface ICredential
{

}

Is there a way to save the casting of ICredential to MyCredential in MyCollector's Constructor? 有没有办法在MyCollector的构造函数中保存ICredential到MyCredential的转换? I don't have option to put Username and AuthToken in ICredential as it's implemented by two different Credentials that both have different set of properties. 我没有选择将Username和AuthToken放在ICredential中,因为它是由两个具有不同属性集的不同凭据实现的。 CollectorFactory will be returning different MyCollector instances in the future and both need to have different credentials. CollectorFactory将来会返回不同的MyCollector实例,并且两者都需要具有不同的凭据。

Any help would be really appreciated. 任何帮助将非常感激。

我不认为你可以实现不同的凭证并尝试将它们用于ICredential。

Here is a way of doing this using generics. 这是使用泛型的方法。 Please read my comments in the code. 请在代码中阅读我的评论。

public class CollectorFactory<T>
{
    public T Create(ICredential credential)
    {
        return (T)Activator.CreateInstance(typeof(T), credential);
    }
}

public class MyCollector : BaseCollector
{
    public dynamic Credential { get; private set; }

    public MyCollector(ICredential credential)
        : base(credential)
    {
        this.Credential = credential;
    }

    // Having this method here limits your ability to make it more generic. 
    // Consider moving this to MyCredential since it refers to specific properties in MyCredential. 
    // If that is not what you want, then you must do a type check before calling methods/ accessing props in Credentials.
    public void Show()
    {
        Console.WriteLine(this.Credential.Username);
        Console.WriteLine(this.Credential.AuthToken);
    }
}

public class MyCredential : ICredential
{
    public string Username { get; set; }

    public string AuthToken { get; set; }
}

public abstract class BaseCollector : ICredentialCollector
{
    protected BaseCollector(ICredential credential)
    {
        if (credential == null)
        {
            throw new ArgumentNullException(nameof(credential));
        }
    }
}

public interface ICredentialCollector
{
}

public interface ICredential
{
}

// test implementation
public class TestClass
{
    public void AuthFactoryTest()
    {
        // test auth instance
        MyCredential auth = new MyCredential() {AuthToken = "asfgasdgdfg", Username = "xuser"};

        // Create test factory
        var fact = new CollectorFactory<MyCollector>(); 
        var myCollector = fact.Create(auth);

        // Do what you need to do to collector object
        myCollector.Show();
    }
}

Generics isn't the solution in this case. 在这种情况下,泛型不是解决方案。 The issue here is that your factory is returning a specific type ( MyCollector ). 这里的问题是你的工厂正在返回一个特定的类型( MyCollector )。 A solution around this would be the following: 解决此问题的解决方案如下:

public class CollectorFactory
{
    public static ICollector Create(MyCredential credential)
    {
        return new MyCollector(credential);
    }
    public static ICollector Create(OtherCredential credential)
    {
        return new OtherCollector(credential);
    }
}

public interface ICollector
{
    void Show();
}

public class MyCollector : ICollector 
{

    public MyCredential Credential { get; set; }

    public MyCollector(MyCredential credential)
    {
        this.Credential = credential;
    }

    public void Show()
    {
        Console.WriteLine(this.Credential.Username);
        Console.WriteLine(this.Credential.AuthToken);
    }
}

public class MyCredential : ICredential
{
    public string Username{ get; set;  }

    public string AuthToken { get; set; }
}

public interface ICredential
{

}

The above is pretty much the canonical example of the Factory design pattern. 以上几乎是Factory设计模式的典型例子。

Instead of overloads you could also do typechecking in the factory: 您也可以在工厂中进行类型检查,而不是重载:

public class CollectorFactory
{
    public static ICollector Create(ICredential credential)
    {
        if(credential.GetType() == typeof(MyCredential))
            return new MyCollector((MyCredential) credential);
        if(credential.GetType() == typeof(OtherCredential ))
            return new OtherCollector((OtherCredential ) credential);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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