我使用接口,继承和泛型在c#中编写了以下代码:
public interface IBasic
{
}
public class Basic : IBasic
{
}
public class AnotherBasic : Basic
{
}
public interface IWorker<in TBasic>
{
void Run(TBasic basic);
}
public class Worker : IWorker<Basic>
{
public void Run(Basic basic)
{
throw new System.NotImplementedException();
}
}
public class AnotherWorker : IWorker<AnotherBasic>
{
public void Run(AnotherBasic basic)
{
throw new System.NotImplementedException();
}
}
public void Test()
{
List<IWorker<IBasic>> workers = new List<IWorker<IBasic>>
{
new Worker(),
new AnotherWorker()
};
}
此代码的问题在于,工作者和其他工作者类不适合作为工作者和基本类的工作者父母的IWorker<IBasic>
的泛型列表。问题是IWorker<in TBasic>
因为运行方法签名而具有逆变性,但我需要它协变,以填充List<IWorker<IBasic>>
。 run方法必须有TBasic参数,我需要这个工作列表,目的是责任链设计模式。我是否错过了某些内容,或者我找到了使协方差和逆变不相互排斥的理由?
答案 0 :(得分:0)
您可以像这样初始化它:
public void Test()
{
List<IWorker<IBasic>> workers = new List<IWorker<IBasic>>
{
new Worker<IBasic>(),
new AnotherWorker<IBasic>()
};
workers[0].Run(new Basic());
}
答案 1 :(得分:0)
你的工人声明说“这是工人名单,每个人都可以执行任何IBasic”,但事实并非如此。
你可以尝试的是将工人可以处理的那种命令的责任转移给工人本身(事实上,这就是chain of responsibility pattern建议的那样)。
public interface IWorker
{
bool DidRun<TBasic>(TBasic basic);
}
public class WorkerChain
{
private readonly List<IWorker> workers = new List<IWorker>
{
new Worker(),
new AnotherWorker()
};
public bool DidRun<T>(T basic)
{
return workers.Any(worker => worker.DidRun(basic));
}
}
public class Worker : IWorker
{
public bool DidRun<T>(T basic)
{
if (!(basic is Basic))
{
return false;
}
Console.WriteLine($"running {basic}");
return true;
}
}
public class Test
{
public void CanRunWorkBasic()
{
var didRun = new WorkerChain().DidRun(new Basic());
Debug.Assert(didRun);
}
}
答案 2 :(得分:0)
如果要将工作人员插入列表,则需要非通用接口IWorker
并且IWorker<TBasic>
必须实现该接口。然后在IWorker
中使用IWorker<TBasic>
代替List
。现在,将工作人员添加到List
不再有问题。
这样我们就解决了一个问题,但遗憾的是我们还创建了另一个问题,因为我们必须两次实现Run
方法。一次用于非通用接口,第二次用于通用接口。
您可以使用抽象Worker
类来克服此问题,默认情况下,在调用非泛型Run
时,会进行必要的检查,转换参数并将其传递给泛型{{1} }} 方法。然后你的工人可以从Run
开始,每个人都可以发挥自己的作用。
在下面的示例中,我试图说明在我看来这个代码应该是什么样子。非通用Worker
方法已实施explicitly,为了安全起见,我还使用了generic type constraints。 Run
方法只检查类型并进一步传递。
Run
答案 3 :(得分:0)
经过2天的学习和调查后,我回答了自己的问题。这是代码:
公共接口IBasic {
}
public class Basic : IBasic
{
}
public class AnotherBasic : Basic
{
}
public interface IWorker<in TBasic>
{
void Run(TBasic basic);
}
public class SimpleWorker : IWorker<IBasic>
{
public void Run(IBasic basic)
{
throw new System.NotImplementedException();
}
}
public class Worker : IWorker<Basic>
{
public void Run(Basic basic)
{
throw new System.NotImplementedException();
}
}
public class AnotherWorker : IWorker<AnotherBasic>
{
public void Run(AnotherBasic basic)
{
throw new System.NotImplementedException();
}
}
public class Final
{
public void Test()
{
List<IWorker<AnotherBasic>> workers = new List<IWorker<AnotherBasic>>
{
new SimpleWorker(),
new Worker(),
new AnotherWorker()
};
}
}
CONTRAVARIANT中的TBasic,这意味着声明应尽可能最具体,如代码所示:AnotherBasic 然后接受较少派生的类型,即父项,接受,并编译代码。