Adding list into system attribute - c#

I have created custom attribute that is part of MEF where I would like to define list of ids that are relevant to the class so I can query on them.
Also the class has to contain definition within itself, this is important that is why i thought about using:
[SignalSystemData("ServiceIds", new List<int>(){1})]
How shall I proceed?
My implementation of search is as follows:
var c = new Class1();
var v = c.EditorSystemList;
foreach (var lazy in v.Where(x=>x.Metadata.LongName=="ServiceIds"))
{
if (lazy.Metadata.ServiceId.Contains(serviceIdToCall))
{
var v2 = lazy.Value;
// v2 is the instance of MyEditorSystem
Console.WriteLine(serviceIdToCall.ToString() + " found");
}else
{
Console.WriteLine(serviceIdToCall.ToString() + " not found");
}
}
My Export class with definition should look like this:
[Export(typeof(IEditorSystem))]
[SignalSystemData("ServiceIds", new List<int>{1})]
public class MyEditorSystem1 : IEditorSystem
{
void test()
{
Console.WriteLine("ServiceID : 1");
}
}
public interface IEditorSystem
{
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class SignalSystemDataAttribute : ExportAttribute
{
public SignalSystemDataAttribute(string longName, List<int> serviceId)
: base(typeof (IEditorSystem))
{
LongName = longName;
ServiceId = serviceId;
}
public string LongName { get; set; }
public List<int> ServiceId { get; set; }
}
public interface IEditorSystemMetadata
{
string LongName { get; }
List<int> ServiceId { get; }
}

To get around the compile time constant issue, you have the following choices:
Use a specially formatted string (i.e. a comma separated list of integers, as you already suggested).
Use a number of overloads, each with a different number of arguments for the IDs. This will get messy if you have too many IDs to be passed.
Use params int[] ids as the last argument to your constructor. This will work, but is not CLS compliant - if that matters for you.
Most easily use an array int [] argument.
Of course you could also use a combination of the above. Having a couple of overloads with say 1 to 5 ID arguments and providing a string argument or params int[] argument for those (hopefully) corner cases, where the overload arguments are not sufficient.
Update: Just found this question/answer. Might not be duplicate as such, but deals with the same issue (mostly).

Related

Interface Method with different type of arguments

I'm constructing a set of filter-classes which will all have the same method 'Applyfilter'.
How should I define the interface which contains apply filter? The only issue is that apply filter can take a second argument of various types e.g. int, string, Lists. Some pseudo code.
Current Interface method:
Data ApplyFilter(input-data, object value);
Example:
public *data* ApplyFilter(input-data, ***string color***) {
// Do something with to data with the color string
}
public *data* ApplyFilter(input-data, ***List<int> size***) {
// Do something with to data with the size list
}
If I defined the type of argument two as an 'object'. I can do some validation within the ApplyFilter function.
As mentioned here: Check if Object is Dictionary or List but is there a better way to do this?
For centralized code , you can create a filter properties class
public class FilterProperties
{
public string Color { get; set; }
public List<int> Sizes { get; set; }
//add filter properties as you want
}
Then create an ApplyFilter method that takes this class as an argument
public object ApplyFilter(List<object> inputData , FilterProperties filterProperties)
{
var queryable = inputData as IQueryable<object>;
// if the color property has value , then filter with it ,else don't filter
if (!string.IsNullOrEmpty(filterProperties.Color))
{
queryable = queryable.Where(//your condition
);
}
if (filterProperties.Sizes.Count > 0)
{
queryable = queryable.Where(//your condition
);
}
}
Now you have one filter method to avoid duplicating code, and have the flexibility to add new optional filters easily.
An approach would be to use Generic
For exemple:
public interface Filter
{
string ApplyFilter<T>(string inputData, T secondArgument);
}
public class MyImplementationClass : Filter
{
public string ApplyFilter<T>(string inputData, T secondArgument)
{
throw new NotImplementedException();
}
}
public class UseCase
{
MyImplementationClass myImplementationClass = new MyImplementationClass();
void applyFilter()
{
string color="";
myImplementationClass.ApplyFilter<string>("input-data", color);
List<int> size=new List<int>();
myImplementationClass.ApplyFilter<List<int>>("input-data", size);
}
}

Distinct List of object in C#

I have to distinct list of object but NOT only by ID because sometimes two different objects have same ID.
I have class:
public class MessageDTO
{
public MessageDTO(MessageDTO a)
{
this.MsgID = a.MsgID;
this.Subject = a.Subject;
this.MessageText = a.MessageText;
this.ViewedDate = a.ViewedDate;
this.CreatedDate = a.CreatedDate;
}
public int? MsgID { get; set; }
public string Subject { get; set; }
public string MessageText { get; set; }
public System.DateTime? ViewedDate { get; set; }
public System.DateTime? CreatedDate { get; set; }
}
How I can distinct list of:
List<MessageDTO> example;
Thanks
Use LINQ.
public class MessageDTOEqualityComparer : EqualityComparer<MessageDTO>
{
public bool Equals(MessageDTO a, MessageDTO b)
{
// your logic, which checks each messages properties for whatever
// grounds you need to deem them "equal." In your case, it sounds like
// this will just be a matter of iterating through each property with an
// if-not-equal-return-false block, then returning true at the end
}
public int GetHashCode(MessageDTO message)
{
// your logic, I'd probably just return the message ID if you can,
// assuming that doesn't overlap too much and that it does
// have to be equal on the two
}
}
Then
return nonDistinct.Distinct(new MessageDTOEqualityComparer());
You can also avoid the need for an extra class by overriding object.Equals(object) and object.GetHashCode() and calling the empty overload of nonDistinct.Distinct(). Make sure you recognize the implications of this decision, though: for instance, those will then become the equality-testing functions in all non-explicit scopes of their use. This might be perfect and exactly what you need, or it could lead to some unexpected consequences. Just make sure you know what you're getting into.
I you want to use other properties, you should implement IEqualityComparer interface. More on: msdn
class MsgComparer : IEqualityComparer<MessageDTO>
{
public bool Equals(MessageDTO x, MessageDTO Oy)
{
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(MessageDTO m)
{
//it must br overwritten also
}
}
Then:
example.Distinct(new MsgComparer());
You could also overwrite Equals in MessageDTO class:
class MessageDTO
{
// rest of members
public override bool Equals(object obj)
{
// your stuff. See: http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx
}
public override int GetHashCode()
{
}
}
Then it's enough:
example.Distinct();
You could use the extension method DistinctBy from the MoreLinq library:
string[] source = { "first", "second", "third", "fourth", "fifth" };
var distinct = source.DistinctBy(word => word.Length);
See here:
I recommend you using solution of #Matthew Haugen
In case you don't want to create a new class for that, there is a way to use LINQ by grouping you list by distinct field(s) then select the first item on this group. For example:
example.(e => new { e.MsgID, e.Subject }).Select(grp => grp.FirstOrDefault());

Method to handle objects with properties in common, but different object types

I have a large collection of automatically generated objects. Although they are all of different, non-related classes, all of the objects share some basic properties (name, id, etc.). I do not control the generation of these objects, so unfortunately I cannot take the ideal approach of implementing an interface. I would like to create a method in which I pass an arbitrary one of these objects and do something using these common properties.
The general idea would be something like:
someObj a = new someObj();
a.name = "sara";
diffObj b = new diffObj();
b.name = "joe";
string phrase = string.Format("I am with {0} and {1}",
getName(a), getName(b));
private string getName(object anyObjWithName)
{
return anyObjWithName.name;
}
though naturally this does not work.
I thought a generic method might hold the answer, but the only way I can see to call it with the current type is using genericMethod.Invoke , which still carries the same issue of not being able to resolve the properties of the passed object in the method. This is unlike Calling generic method with a type argument known only at execution time or How to call generic method with a given Type object? where only the type, or properties of the type, are used in the method, as opposed to properties of the object.
I am aware that this would be (very) prone to error, but I can guarantee that all objects encountered will have the common properties being manipulated.
I can guarantee that all objects encountered will have the common properties being manipulated
If that's the case, you can use dynamic:
private string getName(dynamic anyObjWithName)
{
return anyObjWithName.name;
}
Be aware that using any object that does not have a name property will not fail until run-time.
If you want to add a little bit of safety you can catch the RuntimeBinderException that gets thrown if the property does not exist:
private string getName(dynamic anyObjWithName)
{
try {
return anyObjWithName.name;
}
catch(RuntimeBinderException) {
return "{unknown}";
}
}
If you're unhappy with the performance using dynamic as mentioned by D Stanley, you could always try FastMember.
All you need to know to start using it is pretty much shown in the first 2 code examples.
You are creating a Rube Goldberg device there. You should just have all your data objects classes implement a single interface, then you can work on that. Much simpler and less error prone than fiddling with reflection.
The very fact that a lot of objects have common properties but don't share the same ancestry, on in the very least a common interface, shows that something is wrong with your design. Do rethink it.
Multiple ways to accomplish this, simplest probably is to create Interface and declare common methods there, have your object implement it, then change "getName" method take interface object
private string getName(IMyInterface anyObjWithName)
{
return anyObjWithName.name;
}
The correct way to do this is with an interface, if you own the types that you're working with
public interface IEntity
{
int ID { get; set; }
string Name { get; set; }
}
public class TypeOne : IEntity
{
public int ID { get; set; }
public string Name { get; set }
public string BespokePropertyOne { get; set;}
}
public class TypeTwo : IEntity
{
public int ID { get; set; }
public string Name { get; set; }
public float BespokePropertyTwo { get; set; }
}
static void Main(string[] args)
{
List<IEntity> entities = new List<IEntity>();
entities.Add(new TypeOne() { ID = 1, Name = "Bob", BespokePropertyOne = "blablabla" });
entities.Add(new TypeTwo() { ID = 2, Name = "Alice", BespokePropertyTwo = 5.4f });
foreach (IEntity entity in entities)
{
Console.WriteLine("ID: {0} Name: {1}", entity.ID, entity.Name);
}
}
This answer was written before the edit to the question stating that interfaces weren't possible in this case. Perhaps it can help someone else reading this question.
Interface:
interface Iname
{
string Name { get; set; }
}
Use interface:
class A : Iname
{
public string Name { get; set; }
}
class B : Iname
{
public string Name { get; set; }
}
The method:
string GetName(Iname o)
{
return o.Name;
}
Use:
A a = new A { Name = "First" };
B b = new B { Name = "Last" };
Text = GetName(a) + " " + GetName(b);

LINQ Union different types - dynamically casting to an interface?

I have 10 tables which are presenting to LINQ as different types, but share exactly the same properties. When I try to run a union on them, the compiler tells me that:
"Argument 2: cannot convert from 'System.Collections.IEnumerable' to 'System.Collections.Generic.IEnumerable<LINQPad.User.TelJun2011>'"
The code looks like this
var jul = (from n in TelJul2011s select n);
var jun = (from p in TelJun2011s select p);
jun.Union(jul).Dump();
I've done my research and understand that unions cannot be performed across different types, I also understand that unions can be performed on anonymous types if they share the same properties. This option will not work for me, as I need all the properties from all the tables and don't want to have to type out the same anonymous type 10 times - once for each variable. I want the compiler to infer that they are all the same type based on the fact that all properties are identical.
I've already tried casting to an IEnumberable, Iqueryable, Datatable etc. using both the AsQueryable() type functions, and the "as" keyword. None of that seems to do the trick for me.
I'm wondering if there is some way of doing this by casting dynamically to a parent type. I can't edit the initial declarations of the classes, so can't implement a common interface on them to cast to. But is there some way I can downcast the types into a common interface when they are used, without writing a conversion from each type to a parent interface?
Thanks for any advice!
The result of the Union will be an IEnumerable<Xxx> but in this case you have to specify what Xxx is. If the types TelJun2011 and TelJul2011 are not structs (value-types), you can utilize the covariance of IEnumerable<out T> like this:
jun.Union<object>(jul)
This works because TelJun2011 and TelJul2011 are both object, and then by covariance IEnumerable<TelJun2011> and IEnumerable<TelJul2011> are both IEnumerable<object>.
Of course object does not possess all the properties common to TelJun2011 and TelJul2011. It would be better if these two types had a more useful common base class or implemened a common interface, because then you could say e.g.:
jun.Union<ITelMonth>(jul)
where ITelMonth were some type containing the common properties you want.
The "problem" is that C#'s static typesystem won't allow what you're trying to achieve. You will have to cast the objects to a base type before union-ing them. That means if both have just System.Object in common, you would have to cast it either to object or (for .net 4.0) to dynamic.
The latter will force a dynamic typechecking:
class A
{
public int Integer { get; set; }
}
class B
{
public int Integer { get; set; }
}
class Program
{
public static void main(string[] args)
{
var a = new[] { new A { Integer = 5 }, new A { Integer = 6 }, new A { Integer = 7 } };
var b = new[] { new B { Integer = 1 }, new B { Integer = 2 }, new B { Integer = 3 } };
var u = a.Cast<dynamic>().Union(b).ToArray();
var i1 = u[0].Integer;
var i2 = u[1].Integer;
var i3 = u[2].Integer;
var i4 = u[3].Integer;
var i5 = u[4].Integer;
var i6 = u[5].Integer;
}
}
In my opinion this is not an ideal solution, but this might help you.
If you're using EntityFramework (or any other framework, I guess), the classes auto-generated are marked as partial, such as the following:
/Project/Data/TelJun2011.cs
namespace Project.Data
{
using System;
using System.Collections.Generic;
public partial class TelJun2011
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
/Project/Data/TelJul2011.cs
namespace Project.Data
{
using System;
using System.Collections.Generic;
public partial class TelJul2011
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
What partial means is that you can create another file for the same class. The generated classes don't implement an interface, but you can easily make then implement your custom interface like this:
/Project/Data/ITelMonth.cs
namespace Project.Data
{
public interface ITelMonth
{
int Id { get; set; }
string Name { get; set; }
string Description { get; set; }
}
}
/Project/Data/Partial/TelJun2011.cs
namespace Project.Data
{
public partial class TelJun2011 : ITelMonth { }
}
/Project/Data/Partial/TelJul2011.cs
namespace Project.Data
{
public partial class TelJul2011 : ITelMonth { }
}
And having correctly defined the interfaces, then we can simply do this:
var jul = (from n in TelJul2011s select (ITelMonth)n);
var jun = (from p in TelJun2011s select (ITelMonth)p);
var bimester = jun.Union(jul);
And you can even access the common properties like such:
foreach (var e in bimester)
{
e.Id.Dump();
}

List which accept only few types

Does there exist in any System namespace in C# a container, which can accept only some types?
For example I want to create my list in which I'll have only objects with type Class1 and int:
//accept only type Class1 and int;
MYLIST lst = new MYLIST(typeof(Class1), typeof(int));
lst.Add( 23 ); // OK
lst.Add( new Class1() ); // OK
lst.Add( "text" ); // wrong, not accepted type
Is something like that in .NET or I have to write it on my own? Thanks.
The C# type system does not allow you to express something like "either Class1 or int". Having said that, you can use overloads to get half of the way there:
class MyClass
{
private List<object> _items = new List<object>();
public void Add(int value) { _items.Add(value); }
public void Add(Class1 value) { _items.Add(value); }
...
}
The real tricky question is how you get things out, rather than how you put things in. There are several possibilities: get everything out as object (by implementing IEnumerable<object>), and maybe special methods like GetInt(int index) and GetClass1(int index).
The answer is NO, there is NO such list in C# and for VERY GOOD reason.
You could make a wrapper, but i'd advise against it.
public class CustomListWrapper< T, F>
{
private readonly List<object> internalList;
public CustomListWrapper()
{
this.internalList = new List<object>();
}
public void Add(object item)
{
if(!(item is T || item is F))
throw new Exception();
this.Add(item);
}
}
PS: before the downvote, for how to get the object out...well this is why this is a fairly bad idea, but you'd have to do an "is" on the type you get out to be able to cast it to the proper type.
Again, not exactly sure why you would EVER need to do this.
No. You will have to create your own. You can implement ICollection or IEnumerable or IList or whatever. You have lots of flexibility here. But bottom line, the answer is no, no such collection exists that allows you to limit the types in the collection to certain types automatically.
You cannot achieve this in a direct way. The item type of a List<T> must be a base type common to all the types you want to add to the list.
You could have a List<object> or a wrapper around a List<object> of cause. However, you would have to check at runtime if the items added to it are of the correct types and you would have to cast the items that you retrieve from the list to the correct type.
If you want to store different types in the same list, a good option would be to create an interface that all of these types must implement
public interface ICommonInterface
{
int Number { get; }
string Text { get; }
}
public Class1 : ICommonInterface
{
public int Number { get; set; }
public string Text { get; set; }
public string AnAdditionalProperty { get; set; }
}
public NumberWrapper : ICommonInterface
{
public NumberWrapper (int number)
{
this.Number = number;
this.Text = number.ToString();
}
public int Number { get; private set; }
public string Text { get; private set; }
}
public TextWrapper : ICommonInterface
{
public TextWrapper (string text)
{
this.Text = text;
int i;
Int32.TryParse(text, out i);
this.Number = i;
}
public int Number { get; private set; }
public string Text { get; private set; }
}
Then you can declare your list as
List<ICommonInterface> lst = new List<ICommonInterface>();
lst.Add(new Class1());
lst.Add(new NumberWrapper(77));
lst.Add(new TextWrapper("hello"));
Console.WriteLine(lst[0].Text);
why not just wrap a List<>, and make two add methods, one that accepts int, another that accepts Class1

Categories