简体   繁体   中英

How can I create an object which acts as a “contract” for data (e.g an integer) to be placed there later?

I'm populating an object[] with items of different types - eg [string, int, DateTime]. Some values depend on data that only becomes available later (in real-time). I would like to create a "contract" for this data in the array, and then later when the data is available, swap out the "contract" object for the actual data. So if it is a Contract, then I can change the Contract to a string later on. I am using the term "contract" here in a unique way, not necessarily relevant to any other uses of the term that you may be familiar with. I'm open to dropping this term if it becomes confusing, it just helped me conceptualize my use case.

At first I tried overloading the int cast operator:

// Expected types: string, int, DateTime
object[] Item = new object[] { 
    "hello", new Contract<int>(), DateTime.Now()
}

public class Contract<T>
{
    public static implicit operator int(Contract<T> Contract)
    {
        // Here the data would be actually resolved
        return 0;
    }
}

However, in the client code (in a referenced assembly I have no control over) where object[] Item is used, I get the following error: expected System.Int32 but found Namespace.Contract `1[System.Int32] . Apparently, the client code expects an Int32 value but receives an Int32 boxed inside a Contract, if I understand this error message (I might not).

One way I thought of trying to do this was:

// Expected types: string, int, DateTime
object[] Item = new object[] { 
    "hello", new Contract<int>(), DateTime.Now()
}

// Interface to allow creating a List of generics
public interface IContract {}

List<IContract> Contracts = new List<IContract>();

public class Contract<T> : IContract
{
    public Contract()
    {
        Contracts.Add(this);
    }    

    public static implicit operator int(Contract<T> Contract)
    {
        // Here the data would be actually resolved
        return 0;
    }
}

// And later on
foreach (var Contract in Contracts)
{
    Contract = (int)(Contract<int>)Contract;
}

But for obvious reasons foreach iteration variables are immutable.

The difficulty is that when the client code comes to evaluate the contents of the array, it expects an integer but finds a boxed value. If it was dynamic, it would still encounter a Contract object rather than the int it expects. I overloaded the int cast operator in hopes that it would perform a cast to the type it expects, but it does not. I really need some way of either a) automatically unboxing the type when the client code evaluates it or b) manually unboxing the type myself just beforehand.

Any ideas on how to proceed? I'm open to changing to a different pattern entirely. The thought of initializing the object[] without the correct data in the first place seems misguided. If there is a better way to resolve the array data at the time the data becomes available, I'm interested.

Changed direction a little and now have a workable solution.

// First, got rid of the complicated generic and interface
public class Contract
{
    // The target array to modify
    public object[] Target { get; set; }
    // Index to the item in the target array
    public int Index { get; set; }

    public void Resolve()
    {
        // Change the value stored in the target array from Contract to int
        Target[Index] = 0;
    }
}

List<Contract> Contracts = new List<Contract>();

// Expected types: string, int, DateTime
object[] Items = new object[] { 
    "hello", new Contract(), DateTime.Now()
}

// A preprocessing step for Items array
foreach (var Item in Items)
{
    if (Item is Contract)
    {
        var Contract = (Contract)Item;
        Contract.Index = Index;
        Contract.Target = Items;
        Contracts.Add(Contract);
    }
}

// Later
foreach(var Contract in Contracts)
{
    Contract.Resolve();
}

The pre-processing step for Items is the main overhead that results from the change. The rest is simplified. The real implementation is a little more complex and has more detailed requirements than shown here. This shows the key concepts for reaching the solution. Thank you to commenters for your assistance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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