![](/img/trans.png)
[英]is there a way to pass unknown amount of types to generic method in C#?
[英]Is there a way to deal with unknown generic types?
我有這個代碼
public interface IConsumable<T> {
void Consume(T item);
}
public interface IProducer<T> {
IConsumable<T> Consumer { get; set; }
void Produce();
}
public class MyClass : MyType,
IConsumable<ISpecifcItem>
{
public void Consume(ISpecificItem item) { ... }
}
public class MySpecificItemProducer
: IProducer<ISpecificItem> {
public IConsumable<ISpecificItem> Consumer { get; set; }
public void Produce() {
ISpecificItem myItem = new MyVerySpecificItem();
Consumer.Consume(myItem);
}
}
然后,我有一個采用任何MyType
的控制器,發現它實現的所有IConsumable<>
類型並獲取通用類型參數的類型。 使用此類型列表,它可以發現實現IProducer<TParam>
所有生產者。 這並不困難:
var consumerTypes =
myType.GetType().GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() ==
typeof(IConsumable<>));
if (consumerTypes.Any()) {
var instanceTypes = consumerTypes
.Select(x => x.GetGenericArguments().First())
.Select(x => typeof(IProducer<>).MakeGenericType(x));
// for each of those types discover classes where
// it assignable from
// and instantiate the class using the Activator
}
但是問題是,如何設置生產者的Consumer屬性? 生產者實例對我來說是一個對象,我不能將其IProducer<T>
轉換為IProducer<T>
,因為我不能像變量一樣使用T。
我可以通過反射producerInstance.GetType().GetProperty("Consumer").SetValue(producerInstance, consumerInstance, null);
但我想知道是否還有另一種方法?
有趣的是,這在運行時失敗了:
MyClass consumerInstance;
dynamic test = producerInstance;
test.Consumer = consumerInstance;
它抱怨consumerInstance的類型與屬性的類型不兼容。
編輯:僅當consumerInstance也是動態的時,動態示例才起作用,例如:
dynamic testC = consumerInstance;
dynamic testP = producerInstance;
testP.Consumer = testC;
不幸的是,如果不重構您提供的代碼,就無法在沒有更多思考的情況下解決問題(如您所做的那樣)。 但是,可以在設置使用者屬性之前使用反射,如果它使您更容易理解。
var method = GetType().GetMethod("Process");
var genericType = interfaceType.GetGenericArguments().First();
var invocable = method.MakeGenericMethod(genericType);
invocable.Invoke(this, new object[] { producer, consumer });
public void Process<T>(IProducer<T> producer, IConsumable<T> consumer)
{
producer.Consumer = consumer;
}
您要為MyType提供> 1 IConsumable並只是更改泛型類型參數嗎? 我想你是因為你得到了這些接口的清單。 我不知道您從何處獲得制作人,但不使用反射的唯一方法是保持反射。 您可以考慮強制每個“ MyType”提供一種“設置”生產者列表的方法(MyType內部會知道所有它們自己的消耗品類型)。 根據將生產者從何處拉出(內部到MyType或外部),可能必須執行以下操作:
public interface IProducer { }
public interface IProducer<T> : IProducer
{
IConsumable<T> Consumer { get; set; }
void Produce();
}
public interface IConsumableProvider
{
void SetupProducers(params IProducer[] producers);
}
public class MyType :
IConsumable<int>,
IConsumable<double>,
IConsumableProvider
{
public void Consume(int item)
{
throw new NotImplementedException();
}
public void Consume(double item)
{
throw new NotImplementedException();
}
public void SetupProducers(params IProducer[] producers)
{
(producers[0] as IProducer<int>).Consumer = (this as IConsumable<int>);
(producers[1] as IProducer<double>).Consumer = (this as IConsumable<double>);
}
}
我不喜歡該解決方案,但我認為最佳解決方案將需要有關您當前代碼庫的更多信息-否則,我給出的答案將與您已經擁有的解決方案過於不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.